Support Forum

Weirdly odd GetNearest() Behavior

Hey!

I am using a grid graph making a Tower Defense like game where you can block the paths of the Enemies coming in. In which case they attack the object that’s blocking their path.

I put 3 objects (walls) down to block the path, and thus the enemy realizes it can’t reach it’s destination so picks the closest object which happens to be a wall in this case. Of course I cannot pass it the wall’s actual position, so I pass in the closest Node’s position. But for whatever reason, it always thinks the closest node is the one behind the object.

If I move the object just a little bit out of line, it finds the correct closest node:

I am not sure why it thinks that the closest node is behind the object and not near.

 private bool CanReachTarget(Entity source, Entity target)
        {
            if (target == null) return false;
            var constraint = NNConstraint.None;

            // Constrain the search to walkable nodes only
            constraint.constrainWalkability = true;
            constraint.walkable = true;
            
            GraphNode sourceNode = AstarPath.active.GetNearest(source.transform.position, constraint).node;
            GraphNode targetNode = AstarPath.active.GetNearest(target.transform.position, constraint).node;

            return PathUtilities.IsPathPossible(sourceNode, targetNode);
        }

My logic for checking the closest node is pretty straight forward, so i believe i might be missing something in the configurations?

I also get weird destination setting. It always tries to go above the object, rather than the shortest path.

I have a building the enemy is trying to attack, and it puts the destination to be above it.

For this I do the same thing, getting the closest node to the destination (which is the buildings position).

Is this something with the way I am using the GetNearest method? or something with my configurations?

Hi

You are trying to find the closest node to that object, but the nodes above it are at the exact same distance as the nodes below it. When that happens, it will pick an arbitrary one, in this case the one above it.

You can make it find the closest node that can be reached by the player, which may be more useful for you:

var closestNodeToPlayer = AstarPath.active.GetNearest(player.position, NNConstraint.Default).node;
var constraint = NNConstraint.None;
constraint.constrainWalkability = true;
constraint.walkable = true;
// Only accept nodes in the same connected component as the player, i.e. that the player can reach
constraint.constrainArea = true;
constraint.area = closestNodeToPlayer.Area;
var nearest = AstarPath.active.GetNearest(p, constraint);

This will give me the closest walkable node from the target, but it doesn’t help with figuring out if the target is reachable because this will always make PathUtilities.IsPathPossible(sourceNode, targetNode); return TRUE.

Is there a way to find the closest node from target that could is walkable but not in the same area? That way I can check isPathPossible.

Another question related to this: Would there be a way to detect which object is blocking a path?

For example, if I A going to C with a clear path, would there be a way to detect what is blocking that path if I were to place an object in the way? I guess I would have to define what those objects are, otherwise anything could be a blocker, even environmental objects. This is where I thought that I might have to use Tags, however, using area could potentially also work.

With Area’s I am thinking to just check the area of the target to see if it’s accessible. If it’s not, figure out the closest entity that is attackable to open that area. Though not sure how I would find that entity that would open up that area. Any idea around that?

The way to do this is to use tags to block the agent. And when you want to figure out which object is blocking, you do a pathfinding request with those tags set to a very high penalty. Go through the list of nodes in the returned path and the first one with the obstacle tag will be the blocking object.