Navmesh How to check if full path available? C#
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);
}
}
}
}
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. $$anonymous$$ight a bit of a handful to program but a grid of locations shouldn't be too expensive computationally.
Thanks for the reply. I've found a way for navmesh to check if the path is complete, I'll post it below.
I was originally going to do what you suggested with A*, but then I discovered unity's navmesh system. It is dynamic enough to recalculate the path and change it in real time, but I want to calculate the path once and apply it to all units so they aren't calculating their own path. Less computationally heavy. I'm not making something as dynamic as an RTS, although I think navmesh would be fine for an RTS, it's more like a turn based strategy game. Since you won't be placing buildings when enemy units are spawning.
I got navmesh to do what I wanted with it, and it seems to run well, but since I'm developing for mobile I want the system to be as less expensive computationally as possible.
Answer by Waffle_Dragon · Jun 05, 2016 at 01:17 AM
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()
Unfortunately this does not work on large complex levels. Here's demonstration.