- Home /
Predict enemy position in X seconds?
Below you can see a method that tries to predict the enemy movement in X seconds, but it's not accurate enough, if you could find any messups in my code I'd really appreciate it!
Details:
The enemy walks across a path defined by A* Pathfinding.
I have every waypoint of that path in an array.
Comments explain what I'm doing in the method.
The enemy moves at a perfectly constant speed.
Possible downfalls:
I'm assuming that boundEnemy.Speed is a distance per second variable for this to work.
Actual Code:
/// <summary>
/// Calculates the position of this enemy in x amount of seconds and returns it.
/// </summary>
/// <param name="seconds">Amount of seconds we're predicting ahead.</param>
/// <returns></returns>
public Vector3 GetPositionIn(float seconds)
{
// Setup variables
float distanceExpected = boundEnemy.Speed * seconds;
int expectedTargetWaypoint = currentWaypoint;
float distanceToCover = 0;
while (true)
{
// if statement prevents the error when using expectedTargetWaypoint - 1.
if (expectedTargetWaypoint == 0)
{
// Distance from start to first waypoint
distanceToCover = Vector3.Distance(transform.position, path.vectorPath[expectedTargetWaypoint]);
}
else
{
// Distance from current Waypoint to the Next
distanceToCover = Vector3.Distance(path.vectorPath[expectedTargetWaypoint - 1], path.vectorPath[expectedTargetWaypoint]);
}
// Will you make it to the next waypoint?
if (distanceExpected - distanceToCover > 0)
{
distanceExpected -= distanceToCover;
expectedTargetWaypoint++;
// Made it to the finish, return finish point.
if (expectedTargetWaypoint >= path.vectorPath.Count)
return path.vectorPath[expectedTargetWaypoint -1];
}
else
{
// return the position where we expect this enemy to be after xSeconds at this constant speed.
// if statement prevents the error when using expectedTargetWaypoint - 1.
if (expectedTargetWaypoint == 0)
{
// return a point between A and B depending on the percentage of its full distance we expect to cover.
return Vector3.Lerp(transform.position, path.vectorPath[expectedTargetWaypoint], distanceExpected / distanceToCover);
}
else
{
// return a point between A and B depending on the percentage of its full distance we expect to cover.
return Vector3.Lerp(path.vectorPath[expectedTargetWaypoint -1], path.vectorPath[expectedTargetWaypoint], distanceExpected / distanceToCover);
}
}
}
}
Your logic seems sound. What do you mean by "not accurate enough"? Can you provide examples of a simple set of waypoints, the enemy's current position, and the lookahead "seconds" value that you provide that does not give the answer you expect?
Sure, I'll get back on it tommorow morning, I've made a straight movement level so the data is more logical, and I'll implement some gizmos / debugging for us to get a better idea. :)
Answer by ThePersister · Jun 02, 2015 at 10:09 AM
I've solved it! See code at far bottom of this post :)
The logic was almost sound, but not close enough ;) Making a straight level, I noticed how every bullet my tower would shoot would land just beyond the waypoint the enemy had lastly passed.
Example A. Blue sphere = enemy. Red sphere = targetPos for bullet. Yellow sphere = bullet itself.
I ran through my code with some debugs, and then I realised that the current position of the enemy would not be taken into account if and only if the prediction hadn't reached the target waypoint or beyond, this line right here:
return Vector3.Lerp(path.vectorPath[expectedTargetWaypoint -1], path.vectorPath[expectedTargetWaypoint], distanceExpected / distanceToCover);
Does not take the current position into account, which is no problem, as long as we have to look from the target waypoint and onward, but if we look at the last waypoint, say, waypoint 0, and the enemy has already passed that, then we should be calculating from where the enemy currently is, like from enemy to target with expected distance, instead of from A to B with expected distance, disregarding the enemy.
This fancy talk all rounds up in the code below, the debugs aren't necessary. Note new bool "isPredictingFurtherThanTargetWaypoint" and its usages.
/// <summary>
/// Calculates the position of this enemy in x amount of seconds and returns it.
/// </summary>
/// <param name="seconds">Amount of seconds we're predicting ahead.</param>
/// <returns></returns>
public Vector3 GetPositionIn(float seconds)
{
// Setup variables
float distanceExpected = boundEnemy.Speed * seconds;
int expectedTargetWaypoint = currentWaypoint;
bool isPredictingFurtherThanTargetWaypoint = false;
float distanceToCover = 0;
while (true)
{
// if statement prevents the error when using expectedTargetWaypoint - 1.
if (expectedTargetWaypoint == 0)
{
// Distance from start to first waypoint
distanceToCover = Vector3.Distance(transform.position, path.vectorPath[expectedTargetWaypoint]);
}
else
{
// Distance from current Waypoint to the Next
distanceToCover = Vector3.Distance(path.vectorPath[expectedTargetWaypoint - 1], path.vectorPath[expectedTargetWaypoint]);
}
// Will you make it to the next waypoint?
if (distanceExpected - distanceToCover > 0)
{
distanceExpected -= distanceToCover;
expectedTargetWaypoint++;
isPredictingFurtherThanTargetWaypoint = true;
// Made it to the finish, return finish point.
if (expectedTargetWaypoint >= path.vectorPath.Count)
return path.vectorPath[path.vectorPath.Count - 1];
}
else
{
// return the position where we expect this enemy to be after xSeconds at this constant speed.
// if statement prevents the error when using expectedTargetWaypoint - 1.
if (!isPredictingFurtherThanTargetWaypoint)
{
Debug.Log("Distance Expected: " + distanceExpected + ", Distance to Cover: " + distanceToCover + ", result: " + (distanceExpected / distanceToCover));
// return a point between A and B depending on the percentage of its full distance we expect to cover.
return Vector3.Lerp(transform.position, path.vectorPath[expectedTargetWaypoint], distanceExpected / distanceToCover);
}
else
{
Debug.Log("Distance Expected: " + distanceExpected + ", Distance to Cover: " + distanceToCover + ", result: " + (distanceExpected / distanceToCover));
// return a point between A and B depending on the percentage of its full distance we expect to cover.
return Vector3.Lerp(path.vectorPath[expectedTargetWaypoint -1], path.vectorPath[expectedTargetWaypoint], distanceExpected / distanceToCover);
}
}
}
}
Thank you for your interest in this post and the help you've given :) Some good old debugging and gizmos got the job done.
Gl with your own programming tasks, back to work! :)
Your answer
Follow this Question
Related Questions
How to adjust speed of an object when it is moved by changing its position ??? 0 Answers
Enemy Approaching player and then stopping in front?? 1 Answer
Moving an Object to the vector of other objects on button press using a vector3 array? 0 Answers
How to Have Projectile Reset to Initial Position Relative to Parent 1 Answer
Enemy AI Movement Decision Making 1 Answer