Navmesh How to check if full path available? C#
Asked Answered
A

7

0

I want to have a build mode where you can place buildings on a grid. Then you can press a Ready button to spawn enemy units that will use navmesh to find their way to a target position. But I don’t want players to be able to leave the build mode if there is no path available to the target position. So I want to calculate a path from spawn position to target position and if it is available, store the path, and flag a bool.

Outside of build mode, I want all units to use the same path that was already calculated. What I have so far almost does this. Using the CalculatePath() function however, returns true if just part of the path is available. I want it to only return true if a complete path is available. Otherwise you can leave build mode and the units end up only going part of the way.

As you can see, the enemy unit (Green capsule) finds the shortest path to the target position (Blue cube) and stops part way because there is no path from there to the target position. I dont want this. I want the path bool to only be true if the complete path is available, not just part of the path.

Here is the manager script I’m using to calculate the path.

using UnityEngine;
using System.Collections;
  
public class EnemyUnitManager : MonoBehaviour {  
    public NavMeshAgent spawnPosition;
    Transform targetPosition;
  
    [HideInInspector]
    public bool pathAvailable;
    public NavMeshPath navMeshPath;
  
    void Start() {
        navMeshPath = new NavMeshPath();
        targetPosition = GameObject.FindGameObjectWithTag("Target").transform;
    }
  
    void Update() {
        pathAvailable = spawnPosition.CalculatePath(targetPosition.position, navMeshPath);
    }
}

And this is the script for the enemy unit.

using UnityEngine;
using System.Collections;
  
[RequireComponent (typeof(NavMeshAgent))]
public class Enemy : MonoBehaviour {
  
    public EnemyUnitManager unitManager;
  
    NavMeshAgent unit;
  
	void Start () {
        unit = transform.GetComponent<NavMeshAgent>();
	}
  
	void Update () {
        if (Input.GetButtonDown("Jump")) {
            if (unitManager.pathAvailable == false) {
                Debug.Log("Path not available");
            }
            else {
                unit.SetPath(unitManager.GetComponent<EnemyUnitManager>().navMeshPath);
            }
        }
	}
}
Anguine answered 22/10, 2023 at 9:40 Comment(1)

I've been away from Unity for a while (got sucked into the Elite Dangerous time vacuum!) but I don't think navmesh can act as dynamically as that. However if you're doing something like an RTS and unit/building placement is on a grid as you've shown you could write your own to check the quickest path till it hits an object and then try alternate routes. Might a bit of a handful to program but a grid of locations shouldn't be too expensive computationally.

Condyloma
A
0

Solved It. I’ll post it here for anyone else with the same problem.

Instead of using the bool returned on the CalculatePath() function, you can check the path.status after you have calculated the path.

if (path.status != NavMeshPathStatus.PathComplete) {}.

For anyone interested this is what I did for my code.

using UnityEngine;
using System.Collections;
  
public class EnemyUnitManager : MonoBehaviour {
  
    public NavMeshAgent spawnPosition;
    Transform targetPosition;
  
    [HideInInspector]
    public bool pathAvailable;
    public NavMeshPath navMeshPath;
  
    void Start() {
        navMeshPath = new NavMeshPath();
        targetPosition = GameObject.FindGameObjectWithTag("Target").transform;
    }
  
    void Update() {
        if (/*UI Button Press*/) {
            if (CalculateNewPath() == true) {
                pathAvailable = true;
                print("Path available");
            }
            else {
                pathAvailable = false;
                print("Path not available");
            }
        }
    }
  
    bool CalculateNewPath() {
        spawnPosition.CalculatePath(targetPosition.position, navMeshPath);
        print("New path calculated");
        if (navMeshPath.status != NavMeshPathStatus.PathComplete) {
            return false;
        }
        else {
            return true;
        }
    }
}

As to keep the computational cost down I am calculating the path only when a button is pressed and then checking if the path reaches the target position. I only continue if this is true. I then assign the already calculated path to each enemy unit when they spawn. So they are only updating movement and not calculating their own path.

This works fine for my purposes, but if you would like to update the path while units are spawning, you can call the CalculateNewPath() function more often or put it in Update() and that path will be assigned to all your units. Or you can have each unit calculate their own path with SetDestination()

Anguine answered 22/10, 2023 at 9:41 Comment(4)

This is useful, thanks

Nucleotide

4 years later... Thanks man!

Busse

Thank you so much man

Swane

Unfortunately this does not work on large complex levels. Here's demonstration. https://youtu.be/uqT5c6JM5oM

Nork
S
0

2 years later…thanks!

Sly answered 12/1 at 2:52 Comment(1)

5 years later ...thanks!

Mcgarry
G
0

2019 and this answer still helped me, thanks a lot!

Godbey answered 12/1 at 2:52 Comment(0)
C
0

Here we are in 2020 hahaha, Thanks buddy !

Cryohydrate answered 12/1 at 2:52 Comment(0)
G
0

2022 and this is still helpful :smiley: Thanks man :smiley:

Gosney answered 12/1 at 2:52 Comment(0)
M
0

Thanks A LOT !!!

Motorboating answered 12/1 at 2:52 Comment(1)

Thats excatly what he meant, and that is excatly how game objects are enabled/disabled. Same answer is also in accepted answer. JavaScript is not supported anymore and this is two years old question.

Weiss
S
0

lot of thx from 2023

Selfaggrandizement answered 12/1 at 2:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.