O'Reilly logo

Programming Game AI by Example by Mat Buckland

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Here’s the listing:
Vector2D SteeringBehaviors::Interpose(const Vehicle* AgentA,
const Vehicle* AgentB)
{
//first we need to figure out where the two agents are going to be at
//time T in the future. This is approximated by determining the time
//taken to reach the midway point at the current time at max speed.
Vector2D MidPoint = (AgentA->Pos() + AgentB->Pos()) / 2.0;
double TimeToReachMidPoint = Vec2DDistance(m_pVehicle->Pos(), MidPoint) /
m_pVehicle->MaxSpeed();
//now we have T, we assume that agent A and agent B will continue on a
//straight trajectory and extrapolate to get their future positions
Vector2D APos = AgentA->Pos() + AgentA->Velocity() * TimeToReachMidPoint;
Vector2D BPos = AgentB->Pos() + AgentB->Velocity() * TimeToReachMidPoint;
//calculate the midpoint of these predicted positions
MidPoint = (APos + BPos) / 2.0;
//then steer to arrive at it
return Arrive(MidPoint, fast);
}
Note that arrive is called with fast deceleration, allowing the vehicle to
reach the target position as quickly as possible.
The demo for this behavior shows a red vehicle attempting to interpose
itself between two blue wandering vehicles.
Hide
Hide attempts to position a vehicle so that an obstacle is always between
itself and the agent — the hunter — it’s trying to hide from. You can use
this behavior not only for situations where you require an NPC to hide
from the player — like find cover when fired at — but also in situations
where you would like an NPC to sneak up on a player. For example, you
can create an NPC capable of stalking a player through a gloomy forest,
darting from tree to tree. Creepy!
The method I prefer to effect this behavior is as follows:
Step One. For each of the obstacles, a hiding spot is determined. See Fig
-
ure 3.12.
How to Create Autonomously Moving Game Agents | 107
The Steering Behaviors
These are calculated by the method GetHidingPosition, which looks like
this:
SVector2D SteeringBehaviors::GetHidingPosition(const SVector2D& posOb,
const double radiusOb,
const SVector2D& posTarget)
{
//calculate how far away the agent is to be from the chosen obstacle’s
//bounding radius
const double DistanceFromBoundary = 30.0;
double DistAway = radiusOb + DistanceFromBoundary;
//calculate the heading toward the object from the target
SVector2D ToOb = Vec2DNormalize(posOb - posTarget);
//scale it to size and add to the obstacle's position to get
//the hiding spot.
return (ToOb * DistAway) + posOb;
}
Given the position of a target and the position and radius of an obstacle,
this method calculates a position
DistanceFromBoundary away from the
object’s bounding radius and directly opposite the target. It does this by
scaling the normalized “to obstacle” vector by the required distance away
from the center of the obstacle and then adding the result to the obstacle’s
position. The black dots in Figure 3.12 show the hiding spots returned by
this method for that example.
Step Two. The distance to each of these spots is determined. The vehicle
then uses the arrive behavior to steer toward the closest. If no appropriate
obstacles can be found, the vehicle evades the target.
108 | Chapter 3
The Steering Behaviors
Figure 3.12. Potential hiding spots
Here’s how it’s done in code:
SVector2D SteeringBehaviors::Hide(const Vehicle* target,
vector<BaseGameEntity*>& obstacles)
{
double DistToClosest = MaxDouble
SVector2D BestHidingSpot;
std::vector<BaseGameEntity*>::iterator curOb = obstacles.begin();
while(curOb != obstacles.end())
{
//calculate the position of the hiding spot for this obstacle
SVector2D HidingSpot = GetHidingPosition((*curOb)->Pos(),
(*curOb)->BRadius(),
target->Pos());
//work in distance-squared space to find the closest hiding
//spot to the agent
double dist = Vec2DDistanceSq(HidingSpot, m_pVehicle->Pos());
if (dist < DistToClosest)
{
DistToClosest = dist;
BestHidingSpot = HidingSpot;
}
++curOb;
}//end while
//if no suitable obstacles found then evade the target
if (DistToClosest == MaxDouble)
{
return Evade(target);
}
//else use Arrive on the hiding spot
return Arrive(BestHidingSpot, fast);
}
The demo executable shows two vehicles hiding from a slower, wandering
vehicle.
There are a few modifications you can make to this algorithm:
1. You can allow the vehicle to hide only if the target is within its field
of view. This tends to produce unsatisfactory performance though,
because the vehicle starts to act like a child hiding from monsters
beneath the bed sheets. I’m sure you remember the feeling — the “if
you can’t see it, then it can’t see you” effect. It might work when
you’re a kid, but this sort of behavior just makes the vehicle look
dumb. This can be countered slightly though by adding in a time
effect so that the vehicle will hide if the target is visible or if it has
How to Create Autonomously Moving Game Agents | 109
The Steering Behaviors

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required