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;
}
Hi,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.
Hello,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;
}
***************
Much appreciated!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)
//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;
}