Search code examples
c#unity-game-enginemonodeveloppath-finding

Finding the closer player with NavMesh


In my scene, I have my NavMesh in the center (the yellow one) with 3 cubes set to be tracked. I want the NavMesh to find the closest one with the shortest path to it out of all the cubes and start following it. I have written code to do so, yet it acts weird and I don't see anything wrong with it, but obviously something is. What's happening is when I click play and leave the cubes as is, the NavMesh does, in fact, find the path to the closest cube and start heading towards it (cube3), but when it almost gets to it, the NavMesh takes a hard turn and starts heading towards cube 1 which is obviously not the closer one.

enter image description here

Here is my code. PathLength works just fine. I think the problem lies within the CalcPath function.

float PathLength(Vector3 target){
    NavMeshPath path = new NavMeshPath ();
    myNavMesh.CalculatePath (target, path);
    int i = 1;
    float currentPathLength = 0;
    Vector3 lastCorner;
    Vector3 currentCorner;
    lastCorner = path.corners [0];

    while (i < path.corners.Length) {
        currentCorner = path.corners [i];
        currentPathLength += Vector3.Distance (lastCorner, currentCorner);
        Debug.DrawLine (lastCorner, currentCorner, Color.red,1f);
        lastCorner = currentCorner;
        i++;
    }

    return currentPathLength;
}


void CalcPath(){
    Vector3 closestTarget = Vector3.zero;
    float lastPathLength = Mathf.Infinity;
    float currentPathLength = 0;

    foreach (GameObject player in GameObject.FindGameObjectsWithTag("Player")) {

        currentPathLength = PathLength (player.transform.position);

        if (currentPathLength < lastPathLength) {
            closestTarget = player.transform.position;
        }

        lastPathLength = currentPathLength;
    }

    myNavMesh.SetDestination (closestTarget);
}

Solution

  • You do have an issue in CalcPath. I'll try to give an example to show you what's wrong. Say the distances to the players are as follows: [5,20,10]. Obviously Player A is closest, but CalcPath will return Player C. I'll go through your loop to show why:

    First Iteration:
    currentPathLength : 0 -> 5
    closestTarget : null -> PlayerA.transform.position
    lastPathLength : Mathf.Infinity -> 5

    Second Iteration:
    currentPathLength : 5 -> 20
    closestTarget : PlayerA.transform.position -> PlayerA.transform.position (unchanged)
    lastPathLength : 5 -> 20

    Third Iteration: (this is where your problem lies)
    currentPathLength : 20 -> 10 (this is less than lastPathLength)
    closestTarget : PlayerA.transform.position -> PlayerC.transform.position
    lastPathLength : 20 -> 10

    To fix this issue, instead of storing lastPathLength, store a minimum path length and only change your closestTarget when you have a new minimum.