So far we have looked at the seek, flee, arrival and wander steering behaviors. In this tutorial, I’ll cover the pursuit and the evade behaviors, which make your characters follow or avoid the target.
Note: Although this tutorial is written using AS3 and Flash, you should be able to use the same techniques and concepts in almost any game development environment. You must have a basic understanding of math vectors.
What Is a Pursuit?
A pursuit is the process of following a target aiming to catch it. It’s important to note that the word “catch” makes all the difference here. If something is just following a target, all it has to do is repeat the target’s movements and, as a consequence, it will be on its track.
When pursuing something, the pursuer must follow the target, but it also has to anticipate where the target will be in the near future. If you can predict (or estimate) where the target will be within the next few seconds, it’s possible to adjust the current trajectory to avoid unnecessary routes:
Predicting the Future
As described in the first tutorials the movement is calculated using Euler integration:
position = position + velocity
As a direct consequence, if the current character’s position and velocity are known it is possible to predict where it will be within the next T
game updates. Assuming the character is moving in a straight line and the position we want to predict is three updates ahead (T=3
), the character’s future position will be:
position = position + velocity * T
The key for a good prediction is the right value for T
. If the value is too high, it means the pursuer will end up chasing a ghost. If T
is too close to zero, it means the pursuer is not actually pursuing the target, but it is just following it (no prediction).
If the prediction is calculated for every game frame, it works even if the target is constantly changing its direction. Every update a new “future position” is generated based on the character’s current velocity vector (which also guides the movement direction).
Pursuing
The pursuit behavior works pretty much the same way seek does, the only difference is that the pursuer will not seek the target itself, but its position in the near future.
Assuming every character in the game is represented by a class named Boid
, the following pseudo-code implements the basic idea behind the pursuit behavior:
public function pursuit(t :Boid) :Vector3D { T :int = 3; futurePosition :Vector3D = t.position + t.velocity * T; return seek(futurePosition); }
After the pursuit force calculation, it must be added to the velocity vector just like all previous steering forces:
public function update() :void { steering = pursuit(target) steering = truncate (steering, max_force) steering = steering / mass velocity = truncate (velocity + steering , max_speed) position = position + velocity }
The figure below illustrates the process:
The pursuer (the character at the bottom) will seek the target’s future position, following a trajectory described by the orange curve. The final result will be:
The pursuit behavior using T=30
. Click the demo to show force vectors. The target seeks the mouse.
Improving Pursuit Accuracy
There is a problem when the value of T
is constant: the pursuit accuracy tends to be poor when the target is close. This is because when the target is close, the pursuer will continue to seek the prediction of the target’s position, which is T
frames “away”.
That behavior would never happen in a real pursuit because the pursuer would know it is close enough to the target and should stop predicting its position.
There is a simple trick that can be implemented to avoid that and drastically improve the pursuit accuracy. The idea is very simple; instead of a constant value for T
, a dynamic one is used:
T = distanceBetweenTargetAndPursuer / MAX_VELOCITY
The new T
is calculated based on the distance between the two characters and the maximum velocity the target can achieve. In simple words the new T
means “how many updates the target needs to move from its current position to the pursuer position”.
The longer the distance, the higher T
will be, so the pursuer will seek a point far ahead the target. The shorter the distance, the lower T
will be, meaning it will seek a point very close to the target. The new code for that implementation is:
public function pursuit(t :Boid) :Vector3D { var distance :Vector3D = t.position - position; var T :int = distance.length / MAX_VELOCITY; futurePosition :Vector3D = t.position + t.velocity * T; return seek(futurePosition); }
The final result is:
The pursuit behavior using a dynamic T
. Click the demo to show force vectors. The target seeks the mouse.
Evading
The evade behavior is the opposite of the pursuit behavior. Instead of seeking the target’s future position, in the evade behavior the character will flee that position:
The code for evading is almost identical, just the last line is changed:
public function evade(t :Boid) :Vector3D { var distance :Vector3D = t.position - position; var updatesAhead :int = distance.length / MAX_VELOCITY; futurePosition :Vector3D = t.position + t.velocity * updatesAhead; return flee(futurePosition); }
The final result is the following:
The evade behavior. Click the demo to show force vectors. The target seeks the mouse.
Conclusion
This tutorial described the pursuit and the evade behaviors, which are great to simulate a variety of patterns, such as a group of animals trying to escape from a hunter.
I hope you’ve enjoyed these tips so far and can start using all those behaviors, combining them to create even better patterns! Keep up to date by following us on Twitter, Facebook, or Google+.