Pursuit behavior is useful when an agent is required to intercept a moving
target. It could keep seeking to the current position of the target of course,
but this wouldn’t really help to create the illusion of intelligence. Imagine
you’re a child again and playing tag in the schoolyard. When you want to
tag someone, you don’t just run straight at their current position (which is
effectively seeking toward them); you predict where they are going to be in
the future and run toward that offset, making adjustments as you narrow
the gap. See Figure 3.3. This is the sort of behavior we want our agents to
The success of the pursuit function depends on how well the pursuer can
predict the evaders trajectory. This can get very complicated, so a compro
mise must be made to obtain adequate performance without eating up too
many clock cycles.
There is one situation the pursuer may face that enables an early out: If
the evader is ahead and almost directly facing the agent, the agent should
head directly for the evaders current position. This can be calculated
quickly using dot products (see Chapter 1). In the example code, the
evaders inverted heading must be within 20 degrees (approximately) of
the agent’s to be considered “facing.”
One of the difficulties in creating a good predictor is deciding how far
into the future the agent should predict. Clearly, the amount of look-ahead
should be proportional to the separation between the pursuer and its evader,
and inversely proportional to the pursuers and evaders speeds. Once this
time has been decided, an estimated future position can be calculated for
the pursuer to seek to. Let’s take a look at the code for this behavior:
Vector2D SteeringBehaviors::Pursuit(const Vehicle* evader)
//if the evader is ahead and facing the agent then we can just seek
94 | Chapter 3
The Steering Behaviors
Figure 3.3. Calculating the vectors for the pursuit steering behavior. Once again, the
dotted vector shows how the addition of the steering force to the current velocity pro-
duces the desired result.
//for the evader's current position.
Vector2D ToEvader = evader->Pos() - m_pVehicle->Pos();
double RelativeHeading = m_pVehicle->Heading().Dot(evader->Heading());
if ((ToEvader.Dot(m_pVehicle->Heading()) > 0) &&
(RelativeHeading < -0.95)) //acos(0.95)=18 degs
return Seek(evader->Pos());
//Not considered ahead so we predict where the evader will be.
//the look-ahead time is proportional to the distance between the evader
//and the pursuer; and is inversely proportional to the sum of the
//agents' velocities
double LookAheadTime = ToEvader.Length() /
(m_pVehicle->MaxSpeed() + evader->Speed());
//now seek to the predicted future position of the evader
return Seek(evader->Pos() + evader->Velocity() * LookAheadTime);
TIP Some locomotion models may also require that you factor in some time for
turning the agent to face the offset. You can do this fairly simply by increasing
the LookAheadTime by a value proportional to the dot product of the two head-
ings and to the maximum turn rate of the vehicle. Something like:
LookAheadTime += TurnAroundTime(m_pVehicle, evader->Pos());
Where TurnAroundTime is the function:
double TurnaroundTime(const Vehicle* pAgent, Vector2D TargetPos)
//determine the normalized vector to the target
Vector2D toTarget = Vec2DNormalize(TargetPos - pAgent->Pos());
double dot = pAgent->Heading().Dot(toTarget);
//change this value to get the desired behavior. The higher the max turn
//rate of the vehicle, the higher this value should be. If the vehicle is
//heading in the opposite direction to its target position then a value
//of 0.5 means that this function will return a time of 1 second for the
//vehicle to turn around.
const double coefficient = 0.5;
//the dot product gives a value of 1 if the target is directly ahead and -1
//if it is directly behind. Subtracting 1 and multiplying by the negative of
//the coefficient gives a positive value proportional to the rotational
//displacement of the vehicle and target.
return (dot - 1.0) * -coefficient;
The pursuit demo shows a small vehicle being pursued by a larger one.
The crosshair indicates the estimated future position of the evader. (The
evader is utilizing a small amount of wander steering behavior to affect its
motion. I’ll be covering wander in just a moment.)
How to Create Autonomously Moving Game Agents | 95
The Steering Behaviors

Get Programming Game AI by Example now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.