A* integration wander

nikbates

New member
I keep having issues with the wander task from the movement pack. It constantly tries to pick a wander destination that is outside of the grid.

How do I fix this
 
Can you insert some logging within Wander.TrySetTarget to see if the invalid destination is returning a valid state? Before Wander moves it attempts to sample the position to ensure it is valid.
 
I should have worded that better. It will pick a wander destination, but it doesn't factor in the outside of the graph. If its close to the edge of the walk able area it doesnt matter to its wander destination pick, meaning it will pick a wander spot outside of the graph causing the ai to just stand at the edge looking in the direction of the wander destination
 
The Wander task will randomly pick a destination until SamplePosition returns true. This is done randomly so it may take a few tries for it to return a valid destination, but as soon as SamplePosition returns true then it will move to that position. In this case it sounds like SamplePosition is returning true when you don't think that it should be. The SamplePosition uses AstarPath.active.GetNearest(position).node.Walkable to determine if that position can be traversed. Do you know of a better A* function to use?
 
The flee from the movement pack is also picking a flee destination that is not on the grid graph. It constantly chooses outside of the graph and tries to walk to get, gets to the edge of the graph and then endlessly circles
 
Do you know if there is a better way to sample the position in A* other than the GetNearest function?
 
I think that this is currently a limitation of the A* IAStarAI interface. I will reach out to the A* developer to see if he can add a method that is similar to the NavMesh version.
 
Okay if it is a limitation of the A* asset, why does it say the movement pack is integrated with the A* assets?
And why is there no indication of this on the store page?
 
The integration package covers most use cases but this is the first time that I have received this feedback. Give me a little bit of time to work with the A* developer to come up with a proper solution.
 
I may have a workaround for now - try downloading the A* integration again.
 
Still an issue:
3925a4b5ae0fc09faa8189d1418ad927.png

https://gyazo.com/3925a4b5ae0fc09faa8189d1418ad927

It's not the first time though. I mentioned this a year ago here: http://www.opsive.com/forum/index.php?threads/movement-integration-a-bug.1870/post-9898

I have the latest version of behavior designer, movement pack, astar, and movement pack's astar integration. I'm still getting this same issue. At this point the wander task just isn't worth using as it'll lead to a the AI getting stuck after enough time.

Edit: Still stuck there this entire time I've been typing this. And I just noticed the destination is also above (And outside) the navmesh (mentioned this last year as well):
d730e5b566bd5028caa396475f3a3465.png

https://gyazo.com/d730e5b566bd5028caa396475f3a3465
 
Fixed this for myself, but it's a very specific case for my game. For anyone wondering: I edited SamplePosition in IAstarAIMovement.cs. I added a check for the proposed position to see if it's inside any given graph my AI is currently on.
9cdab03d9b25668eaae6ba43c8989f16.png

https://gyazo.com/9cdab03d9b25668eaae6ba43c8989f16

Kinda ugly, but it works so I'm leaving it as is.

Edit: Also if you're only using 1 graph in your scene, this is much, much easier. Just do:

var direction = transform.InverseTransformDirection(AstarPath.active.GetNearest(position).position - position);
direction.y = 0;
bool isInside = Astar.active.data.<YourGraphType>.PointOnNavMesh(position, NMContraint.None) != null;
if (!isInside)
return false;
return direction.sqrMagnitude < arriveDistance.Value;

In my case I have multiple graphs so I need to do a little extra.
 
Last edited:
Thanks for posting your solution! I didn't know about PointOnNavmesh. I'll see if there is a generic way to retrieve that method.
 
Hi,

To add to this, I experienced the same issue and I do think that the Astar interface is incomplete because of that.

As I had to change it anyway, I changed behaviour slightly so replaced the "SamplePosition" approach with a "GetNearestValidPosition" method as I don't see the point of retrying several random positions when you can get the closest valid one first time. There may be valid use cases but I personally I don't think they apply to a wander-like scenario.

The GetNearestValidPosition is as follows.

C#:
protected Vector3 GetNearestValidPosition(Vector3 position, bool useNodeCenter)
{
    var constraint = NNConstraint.None;
    // Constrain the search to walkable nodes only
    constraint.constrainWalkability = true;
    constraint.walkable = true;
    var nnInfo = AstarPath.active.GetNearest(position, constraint);
    if(useNodeCenter)
        return new Vector3(nnInfo.node.position.x*0.001f,nnInfo.node.position.y*0.001f, nnInfo.node.position.z*0.001f);
    else
        return nnInfo.position;
}

Note that I have observed some issues with using the nnInfo.position above as it seldom ends up in a non-valid node (I have asked for confirmation to Aaron at AstarProject as not related to OPSIVE), in the meantime I'm using nnInfo.node.position, apologies for the ugly conversion to Vector3, it's just a quick patch at the moment.
 
Hi,

To add to this, I experienced the same issue and I do think that the Astar interface is incomplete because of that.

As I had to change it anyway, I changed behaviour slightly so replaced the "SamplePosition" approach with a "GetNearestValidPosition" method as I don't see the point of retrying several random positions when you can get the closest valid one first time. There may be valid use cases but I personally I don't think they apply to a wander-like scenario.

The GetNearestValidPosition is as follows.

C#:
protected Vector3 GetNearestValidPosition(Vector3 position, bool useNodeCenter)
{
    var constraint = NNConstraint.None;
    // Constrain the search to walkable nodes only
    constraint.constrainWalkability = true;
    constraint.walkable = true;
    var nnInfo = AstarPath.active.GetNearest(position, constraint);
    if(useNodeCenter)
        return new Vector3(nnInfo.node.position.x*0.001f,nnInfo.node.position.y*0.001f, nnInfo.node.position.z*0.001f);
    else
        return nnInfo.position;
}

Note that I have observed some issues with using the nnInfo.position above as it seldom ends up in a non-valid node (I have asked for confirmation to Aaron at AstarProject as not related to OPSIVE), in the meantime I'm using nnInfo.node.position, apologies for the ugly conversion to Vector3, it's just a quick patch at the moment.
Hi,
I used your method GetNearestValidPosition() on IAstarAIMovement.cs but my AI behavior still eventually get stuck at the edges of the Graph when wandering...
I am an amateur programmer so I apologize in advance, is this one a correct implementation?

***************
protected bool SamplePosition(Vector3 position)
{
var direction = transform.InverseTransformDirection(GetNearestValidPosition(position, true) - position);
direction.y = 0;
return direction.sqrMagnitude < arriveDistance.Value;
}
***************
 
Hi,
I used your method GetNearestValidPosition() on IAstarAIMovement.cs but my AI behavior still eventually get stuck at the edges of the Graph when wandering...
I am an amateur programmer so I apologize in advance, is this one a correct implementation?

***************
protected bool SamplePosition(Vector3 position)
{
var direction = transform.InverseTransformDirection(GetNearestValidPosition(position, true) - position);
direction.y = 0;
return direction.sqrMagnitude < arriveDistance.Value;
}
***************
Hello,

No, that won't work. The method I posted is alternative to Sample Position. Instead of sampling a random position n times until you find a valid ones, you calculate the closest valid one off a random point.
I'll give you an example when I'm in front of the PC, but from memory you need to invoke getnearestvalidposition directly from the wander class (or whatever movement class you are using)
 
Hello,

No, that won't work. The method I posted is alternative to Sample Position. Instead of sampling a random position n times until you find a valid ones, you calculate the closest valid one off a random point.
I'll give you an example when I'm in front of the PC, but from memory you need to invoke getnearestvalidposition directly from the wander class (or whatever movement class you are using)
Much appreciated!
 
Here's the modified Wander using the GetNearestValidPosition() method. Please note that this implementation will use the centre of the node as nearest valid point rather than the nearest valid point within the astar navmesh, I couldn't get the latter to work consistently whereas this is more realiable but may not be suitable for all needs.
Wander.cs
C#:
//Revised version which takes random point and turns it into  a valid walkable point via GetNearestValidPosition()
//unlike original it does not "attempt" to locate a destination, but gets it right first time.
private bool TrySetTarget()
{
    var direction = transform.forward;
    direction = direction + Random.insideUnitSphere * wanderRate.Value;
    var destination = transform.position + direction.normalized * Random.Range(minWanderDistance.Value, maxWanderDistance.Value);
    SetDestination(GetNearestValidPosition(destination));
    return true;
}
 
I just implemented it in Wander.cs but my AIs eventually still gets stuck at the edge of the graph or against obstacles that create unwalkable areas inside the graph. Maybe it's relevant, but I'm using multiple A* graphs. Even so, the map edges are unwalkable for all AIs.
I even had an instance of an AI reaching the end of the A* graph, disappearing and continuing on the other end in a loop, pacman-style. That was a first!?
 
Top