Generate a random point with a min and max distance away (RichAI + Recast)


#1

Hello,

I was wondering how I can generate a random point that’s let’s say minimum 20 meters away from the AI and maximum 40 meters away, so it will be between 20 - 40. The point must be on the recast graph (walkable for the AI).


#2

Hi

So on recast graphs this is actually pretty tricky to do accurately because the boundary can be very complex:
(below is an image showing all points within a certain distance from the black point on the graph).

There is the RandomPath class which does almost what you want, but the problem is that it only searches node by node and thus you may loose a lot of precision because on recast graphs nodes can be both very small and very large.
For more info about this, take a look at Method 3 here: https://arongranberg.com/astar/docs/wander.html

A more feasible approach could be to pick a random point inside a circle of radius 40 and outside a circle of radius 20 and then check if the distance to that point is still reasonable.

Something like this (not tested):

Vector3 PickRandomPoint (Vector3 around, float minDistance, float maxDistance) {
	Vector3 result = around;
	// Try at most 10 times
	for (int i = 0; i < 10; i++) {
		// Note: This will not generate points uniformly spread out on the surface, but it's reasonably close for this purpose
		float radius = Random.value * (maxDistance - minDistance) + minDistance;
		float angle = Random.value * Mathf.PI * 2;
		Vector3 point = transform.position + new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius;

		// Note: Make sure that the Seeker has a FunnelModifier attached so that we can estimate the path length well
		var path = seeker.StartPath(around, point) as ABPath;
		path.BlockUntilCalculated();
		
		// Skip the path if it failed
		if (path.error) continue;

		var length = path.GetTotalLength();
		result = path.endPoint;
		if (length >= 20 && length <= 40) {
			return result;
		}
	}

	// Fall back to returning the last point in case we couldn't find any point that was valid
	return result;
}

#3

Yes it’s something like “Flee” the AI can pick a point that’s 20 (min) - 40 (max) meters away from its current position, meaning it could pick 20, 21, 22 … 38, 39, 40.

I don’t have path.endPoint though, is it similar to:

            result = path.vectorPath.Last();

#4

Yes, it should be the same thing as long as it has been post processed by the Seeker.
Looks like I missed a cast to ABPath in my code.


#5

Which one is better for performance ABPath or Path?


#6

ABPath is just a subclass of Path. Path is an abstract class that every path type inherits from.


#7

Okay, I already have “Funnel Simplification” checked on the RichAi, so I don’t need to add the FunnelModifier component with that setup, right?


#8

Unfortunately yes. The RichAI script has its own internal funnel algorithm that it runs every frame, only calculating the next corner it needs to move to (it doesn’t process the whole path) but in this case we want to calculate the length of the path after it has been fully post processed. Everything will work without a funnel modifier, but the length estimates will not be as accurate.


#9

Well in that case I will only enable the FunnelModifier when the AI is in the “Flee” / “Hide” state.