Immediately move until the path completes AIPath


#1

In my game I have AI units dodge enemy attacks by moving tangent to the attacker. I do this by setting IAstarAI.destination, which has the expected problem that due to the time it takes pathfinding to complete the enemy still ends up getting hit a good part of the time; especially as more units are involved in combat.

Sometimes the AI only dodges a short distance, sometimes it moves farther, such as backing out of range which could be 5 meters.

I’m using CharacterController on each AI.

Ideally I’d like to set IAstarAI.destination, immediately start moving towards the destination, and when the path calculation completes to find the nearest point on the path and continue from there without jitter.

Would it work to call IAStarAI.SetPath() as soon as I know to dodge, with only the current and end node? Followed by SearchPath()? If so, should I be using ABPath.Construct?

I could call IAStarAI.Move() - however I don’t think that will preserve momentum or use acceleration. I want the unit to move as if they naturally had the path, rather than as if they were on a conveyor belt.

image


#2

hmm, when he dodges you can make a seperate function that finds a path to waypoint currentwaypoint.
then >> foreach currentwaypoint threw oldpath.count newpath.add oldpath


#3

Any official response on this?


#4

Hi

Sorry for the late answer. I’ve been sick during the last few days.
I have not attempted this myself at some point, however I think what you suggest about SetPath would work very well. So you would do:

  1. Call ai.SetPath with a completed path that has a vectorPath with only the current position of the agent and the target point.
  2. Set ai.destination
  3. Call ai.SearchPath() to immediately start searching for a path to the destination instead of waiting for the regularly scheduled path recalculation (controlled by ai.repathRate).

It’s critical that you do 1 before 3, the order of 1 and 2 doesn’t matter much.

Another alternative that might be easier is to simply block until the path is calculated. This will force the path to be calculated immediately and it will be available to the character the next time it does its movement calculations. You can do that like this:

  1. Set ai.destination
  2. Call ai.SearchPath to immediately start searching for a new path
  3. Call seeker.GetPath().BlockUntilCalculated() to force the path to be calculated right now and block until it is calculated. Note that for longer paths this may introduce lag, so it depends on your game if this is a good way to go or not.

#5

Thanks for getting back to me. Hope you feel better.

I’m unsure about what you mean here:
" Call ai.SetPath with a completed path"

The intent is the AI can start moving immediately before the path has completed, because they need to dodge right away. The AI might bump into stuff but I’m willing to accept that or if it’s a problem to do a physics raycast first.

So I want to make a fake path in code that will get AIPath to move right away. As mentioned, I could just use CharacterController.SimpleMove but that would ignore the velocity and acceleration that AIPath handles for me.

So can I create a fake completed path using code?


#6

Okay, it looks like to make it be marked properly as completed you would actually have to access some internal methods, which is perhaps not the best idea.

I have written a method to create a fake path from a list of points which will be included in the next update. You can add it to the ABPath.cs file.

/** Creates a fake path.
 * Creates a path that looks almost exactly like it would if the pathfinding system had calculated it.
 * 
 * This is useful if you want your agents to follow some known path that cannot be calculated using the pathfinding system for some reason.
 * 
 * \snippet MiscSnippets.cs ABPath.FakePath
 * 
 * You can use it to combine existing paths like this:
 * 
 * \snippet MiscSnippets.cs CombinePaths
 */
public static ABPath FakePath (List<Vector3> vectorPath, List<GraphNode> nodePath = null) {
	var path = PathPool.GetPath<ABPath>();
	for (int i = 0; i < vectorPath.Count; i++) path.vectorPath.Add(vectorPath[i]);

	path.completeState = PathCompleteState.Complete;
	((IPathInternals)path).AdvanceState(PathState.Returned);

	if (vectorPath.Count > 0) {
		path.UpdateStartEnd(vectorPath[0], vectorPath[vectorPath.Count - 1]);
	}

	if (nodePath != null) {
		for (int i = 0; i < nodePath.Count; i++) path.path.Add(nodePath[i]);
		if (nodePath.Count > 0) {
			path.startNode = nodePath[0];
			path.endNode = nodePath[nodePath.Count - 1];
		}
	}

	return path;
}

Screenshot of the docs

I haven’t tested it, but I think it should work.


#7

It crashes here:
var graph = AstarData.GetGraph(path.path[0]) as ITransformedGraph;
Because path.path is a 0 length List.

List positions = new List();
positions.Add(transform.position);
positions.Add(aiDestinationGameObject.transform.position);
ABPath fakePath = ABPath.FakePath(positions, null);
AIPath.SetPath(fakePath);
AIPath.SearchPath();


#8

Right. You will also need to replace that line with

var graph = path.path.Count > 0 ? AstarData.GetGraph(path.path[0]) as ITransformedGraph : null;

(this change will also be included in the next update).