Reuse NavMeshPathfinder

Hey Guys

Im trying to implement path finding in a little game I’m building. Ive used NavMeshPathfinder and it worked great. However i decided to that not just my avatar but all my characters need to do path finding…

So should we be using multiple NavMeshPathfinders?
or should they all use the same one?

I had a look at the code and it looks like we should at least use one per character since they will need to path find concurrently. but when i do use multiple new NavMeshPathfinder(worldMap). i get

[java]
java.lang.NullPointerException
at com.jme3.ai.navmesh.Cell.queryForPath(Cell.java:667)
at com.jme3.ai.navmesh.NavMeshPathfinder.buildNavigationPath(NavMeshPathfinder.java:223)
at com.jme3.ai.navmesh.NavMeshPathfinder.computePath(NavMeshPathfinder.java:126)
at jme3test.helloworld.GameCharacterNode.travel(GameCharacterNode.java:166)
[/java]

NavMeshPathfinder is meant to be used with a single agent/actor. so yes if you have multiple npcs youd need multiple NavMeshPathfinder instances.

However you may reuse the same “NavMesh” instance for your many NavMeshPathfinders.

as for your error, to me it looks like your agent isnt correctly on the navmesh. you might want to use the NavMeshPathfinder.warp() to ensure that the agent is seen as being on the navmesh.

edit: actually if youre doing the pathfinding concurrently there may be issues, i havent actually tried it myself. if done sequentially there should no issue though.

I got this same crash and I modified the queryForPath function. Basically, “caller” is being passed to queryForPath as null & the cell is considered “open”, so there is a caller.equals(link[0]) happening – causing the NullPointerException. This is how I modified the code to solve the problem for me:

[java] boolean queryForPath(NavHeap heap, Cell caller, float arrivalCost) {
if (sessionID != heap.getSessionID()) {
// this is a new session, reset our internal data
sessionID = heap.getSessionID();

        if (caller != null) {
            open = true;
            computeHeuristic(heap.getGoal());
            this.arrivalCost = arrivalCost;

            // remember the side this caller is entering from
            if (caller.equals(links[0])) {
                arrivalWall = 0;
            } else if (caller.equals(links[1])) {
                arrivalWall = 1;
            } else if (caller.equals(links[2])) {
                arrivalWall = 2;
            }
        } else {
            // we are the cell that contains the starting location
            // of the A* search.
            open = false;
            this.arrivalCost = 0;
            heuristic = 0;
            arrivalWall = 0;
        }
        // add this cell to the Open heap
        heap.addCell(this);
        return true;
    } else if (caller == null) {
        // caller is null
        return false;
    } else if (open) {
        // m_Open means we are already in the Open Heap.
        // If this new caller provides a better path, adjust our data
        // Then tell the Heap to resort our position in the list.            
        if ((arrivalCost + heuristic) < (this.arrivalCost + heuristic)) {
            this.arrivalCost = arrivalCost;

            // remember the side this caller is entering from
            if (caller.equals(links[0])) {
                arrivalWall = 0;
            } else if (caller.equals(links[1])) {
                arrivalWall = 1;
            } else if (caller.equals(links[2])) {
                arrivalWall = 2;
            }
            // ask the heap to resort our position in the priority heap
            heap.adjustCell(this);
            return true;
        }
    }
    // this cell is closed
    return false;
}[/java]

Note that I renamed the “Heap” class to “NavHeap” (you can keep it “Heap”) – the important change is adding a caller == null check & returning false before going into the “else if(open)” branch. I’m not 100% sure what is going on in this function, though, so this might not be an ideal solution but my AI characters seem to act as expected. Anyway, I hope this gets addressed in the SDK. If someone can let me push this fix somewhere, I’d be more than happy to do it.

1 Like

I think this is actually wrong. I tried it many times but always I try to reuse the same “NavMesh” the object trying to reuse it doesn’t move so I think a new NavMesh(mesh) must also be done (before new NavMeshPathfinder(navMesh)) for each entity that has to pathfind.
I made a fast look to the source to find why is this happening but I didn’t find so I can be wrong (but I don’t think as I made lot of tests).