IsPathPossible fails on some graphs after change to FollowerEntity from RichAI

  • A* version: 5.4.6
  • Unity version: 2022.3.62f2

I had this working fairly well in astar 4.x using RichAI/seeker, but have upgraded to 5.4.6 using FollowerEntity and now I can’t get good results.

I have 4 recast graphs. 3 are used for enemy paths.

My enemy agents have no issue getting path to the target, but my tests using IsPathPossible fail on 2 of the 3 graphs.

Here’s the test method I’m using to manually test if path is possible at runtime.
I manually snap-drag the origin point around the map and call the method every Update().
The end Node is a fixed position that I know is on the graph in a valid spot. The start node is based on the origin point I move around.

I have 3 enemy sizes (small/medium/large). Small is always returning TRUE, medium and large graphs are always returning FALSE.
I have a 4th graph for non-enemies that fly around (they basically ignore cuts and obstacles) but it’s the second graph/index in the list if that matters.

GIFs and screenshots to follow for each graph setup.

The method:

        public void ButtonHandle_rageTest_TestAgentPathPossible()
        { 
            if (this.rageTest_OriginPathPoint == null) return;

            GraphMask startNodeGraphMask = new GraphMask();
            //Debug.Log("startNodeGraphMask: " + startNodeGraphMask.ToString());

            switch(this.rageTest_UnitSize)
            { 
                case CombatUnitSize.Large:
                    startNodeGraphMask = GraphMask.FromGraphIndex(3); // .FromGraphName("Large Enemy Recast Graph");
                    break;
                case CombatUnitSize.Medium:
                    startNodeGraphMask = GraphMask.FromGraphIndex(2); //.FromGraphName("Medium Enemy Recast Graph");
                    break;
                case CombatUnitSize.Small:
                    startNodeGraphMask = GraphMask.FromGraphIndex(0); //.FromGraphName("Small Enemy Recast Graph");
                    break;
            }

            Debug.Log("startNodeGraphMask set for enemy size: " + this.rageTest_UnitSize.ToString() + ", graphMask: " + startNodeGraphMask.ToString());

            NearestNodeConstraint startNodeConstraint = NearestNodeConstraint.Walkable;
            startNodeConstraint.graphMask = startNodeGraphMask;

            var startNode = AstarPath.active.GetNearest(this.rageTest_OriginPathPoint.position, startNodeConstraint).node;
            var endNode = AstarPath.active.GetNearest(LG_LevelManager.instance.PlayerBase.IsPathPossibleTarget.position).node;

            // Check if a path is possible on the graph

            if (PathUtilities.IsPathPossible(startNode, endNode))
            {
                // TODO do we need a min distance check?
                // PATH GOOD
                Debug.Log("PATH GOOD");

                using (Draw.ingame.WithColor(Color.green))
                {
                    Draw.ingame.SolidBox((Vector3)startNode.position, 1);
                    Draw.ingame.SolidBox((Vector3)endNode.position, 1f);
                }
            }
            else
            {
                // NO GOOD
                Debug.Log("PATH BAD");

                using (Draw.ingame.WithColor(Color.red))
                {
                    Draw.ingame.SolidBox((Vector3)startNode.position, 1);
                    Draw.ingame.SolidBox((Vector3)endNode.position, 1f);
                }
            }
        }

The 4 graphs:

Small Enemy Recast Graph

Medium Enemy Recast Graph

Large Enemy Recast Graph

What I’m seeing at runtime:

Small Test (always good)

isPathPossible_small-ezgif.com-optimize

Medium test (always fails)

isPathPossible_med-ezgif.com-optimize

Large test (always fails)

isPathPossible_large-ezgif.com-optimize

            var endNode = AstarPath.active.GetNearest(LG_LevelManager.instance.PlayerBase.IsPathPossibleTarget.position).node;

When you are getting your end node, you are not constraining it to any particular graph. So if the end node happens to be closer to a different graph than the one the start node is in, then it will not be seen as reachable.

I’d pass in the same nearest node constraint as you pass to the GetNearest function for the start node.