[Solved] Bug? Using "Closest On Node Surface" as End/Start Point Snapping allows Seekers to pass through to a different area

I’m creating a top-down 2D game and implemented the A* based on the given example scene. I tested the problem described below in the given example scene to see if I had done something wrong, but the problem exists there as well.

Using “Closest On Node Surface” as End/Start Point Snapping allows Seeker to pass through to a new area in some cases, which I believe isn’t intended.

The image below shows two different areas of my map “connecting” diagonally. The areas still have different Area colors which means there shouldn’t be a possible path. The green arrows represent the movement of a Seeker when issuing two consecutive movements to the area the green arrows point towards.

squeeze

Once the Seeker stops at the end of the first green arrow the Seeker has entered the other Area and can’t go back(Red arrow).

I use this to move the Seeker.

 ai.destination = targetPosition;
 ai.SearchPath();

Only top-right and bottom-right diagonal paths work to pass through this way.

Hi

This is likely due to floating point errors. I suspect that you have the ‘constraint to inside graph’ option enabled. The only thing that option does is to every frame move the agent to the closest valid point on the graph. However if it should happen to be right in that corner it may (due to floating point errors) turn out that it is actually closer to the wrong node. That it is only possible in one direction is just due to floating point errors.

A more stable way to fix this would be to add some additional margin around the nodes to prevent the agent from getting close to those points where things get ambiguous.

Alternatively you could add a check for if the agent has moved to a new node, and that node does not have a connection to the previous node the agent was at, then move the agent back to its previous position.

GraphNode previous;
Vector3 lastPos;
void Update () {
     var closest = AstarPath.active.GetNearest(transform.position, NNConstraint.Default);
     if (closest == previous || previous == null || previous.ContainsConnection(closest)) {
          previous = closest;
          lastPos = transform.position;
     } else {
          transform.position = lastPos;
     }
}

You could probably integrate this with the already existing code for the ‘constrain inside graph’ option to avoid an additional GetNearest call every frame.

I am using AI Lerp for movement, which I should’ve mentioned. The best option you mention for me would probably be to restrict the allowed node surface for a Seeker to move when using “Closest on Node Surface”. I assume this is what you mean by adding some additional margin around the node? I’ll continue to look for where to change the margin for nodes. Any guidance you could give to locate it would be super appreciated.

Hi

Ah, okay. Yeah, then the easiest solution for this would be to tweak the Closest On Node Surface snapping a bit.

I think this would work:

Open the StartEndModifier.cs script and change this line

return start ? path.startPoint : path.endPoint;

to this

return start ? path.startPoint : Vector3.Lerp(path.endPoint, nodePos, 0.01f);

this will nudge the endpoint of the path slightly towards the node center, which I think will resolve this issue.

I really appreciate the quick response and I did just what you said. It kind of introduced a bug in my game which made me laugh. When Seekers in my game are standing still, they initiate a SearchPath to the same position they are standing on right now, called a “StopAction”. With this implementation they slowly move towards the center of the node :joy: I will have to change how Stopping works, but other than that, it seems to work. Since the “first green arrow” movement as described in my first post doesn’t cause them to enter the new area anymore, they will start sliding back to the center of the correct node(which I’ll have to fix).

It works perfectly! Thank you very much!

1 Like