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

switch(msg.Msg)
{
case Msg_PathReady:
//clear any existing goals
RemoveAllSubgoals();
AddSubgoal(new Goal_FollowPath(m_pOwner,
m_pOwner->GetPathPlanner()->GetPath()));
return true; //msg handled
case Msg_NoPathAvailable:
m_Status = failed;
return true; //msg handled
default: return false;
}
}
//handled by subgoals
return true;
}
Goal_MoveToPositions subgoals are processed and continuously monitored
for failure. If one of the subgoals fails, then this goal reactivates itself in
order to replan.
int Goal_MoveToPosition::Process()
{
//if status is inactive, call Activate() and set status to active
ActivateIfInactive();
//process the subgoals
m_Status = ProcessSubgoals();
//if any of the subgoals have failed then this goal replans
ReactivateIfFailed();
return m_Status;
}
Let’s now move on to see how one of the other strategy-level goals works:
Goal_AttackTarget.
Goal_AttackTarget
A bot selects this strategy when it’s feeling healthy and well armed enough
to attack its current target.
Goal_AttackTarget is a composite goal and its
declaration is straightforward.
Goal-Driven Agent Behavior | 395
Examples of Goals Used by Raven Bots
class Goal_AttackTarget : public Goal_Composite<Raven_Bot>
{
public:
Goal_AttackTarget(Raven_Bot* pOwner);
void Activate();
int Process();
void Terminate(){m_iStatus = completed;}
};
All the action happens in the Activate method. First of all any existing
subgoals are removed and then a check is made to ensure the bot’s target is
still current. This is essential because the target may die or move out of the
bot’s sensory horizon while this goal is still active. In the event of this hap
-
pening the goal must exit.
void Goal_AttackTarget::Activate()
{
m_iStatus = active;
//if this goal is reactivated then there may be some existing subgoals that
//must be removed
RemoveAllSubgoals();
//it is possible for a bot's target to die while this goal is active so we
//must test to make sure the bot always has an active target
if (!m_pOwner->GetTargetSys()->isTargetPresent())
{
m_iStatus = completed;
return;
}
Next the bot queries its targeting system to find out if it has a direct shot at
the target. If a shot is possible it selects a movement tactic to follow.
Remember, the weapon system is a completely separate component of the
AI and will always automatically select the best weapon and aim and shoot
at the current target, no matter what goal the bot is pursuing (see Chapter 7
if you need to refresh your memory). This means that this goal must only
dictate how the bot should move while attacking. I have provided Raven
bots with just two choices: If there is space to the left or right of the bot, it
will strafe from side to side by adding
Goal_DodgeSideToSide to its subgoal
list. If there is no room to dodge, the bot simply seeks to the target’s cur
-
rent position.
//if the bot is able to shoot the target (there is LOS between bot and
//target), then select a tactic to follow while shooting
if (m_pOwner->GetTargetSys()->isTargetShootable())
{
//if the bot has space to strafe then do so
396 | Chapter 9
Examples of Goals Used by Raven Bots
Vector2D dummy;
if (m_pOwner->canStepLeft(dummy) || m_pOwner->canStepRight(dummy))
{
AddSubgoal(new Goal_DodgeSideToSide(m_pOwner));
}
//if not able to strafe, head directly at the target's position
else
{
AddSubgoal(new Goal_SeekToPosition(m_pOwner,
m_pOwner->GetTargetBot()->Pos()));
}
}
Depending on the requirements of your game you will probably want to
give your bot a much wider choice of aggressive movement tactics from
which to select. For instance, you might like to add a tactic that moves the
bot to the perfect range for shooting its current (or favorite) weapon or one
that selects a good sniping or cover position (don’t forget, navgraph nodes
can be annotated with this sort of information).
If there is no direct shot at the target — because it may have just run
around a corner — the bot adds
Goal_HuntTarget to its subgoal list.
//if the target is not visible, go hunt it.
else
{
AddSubgoal(new Goal_HuntTarget(m_pOwner));
}
}
The Process method for Goal_AttackTarget is trivial. It just makes sure the
subgoals are processed and that the goal replans if a problem is detected.
int Goal_AttackTarget::Process()
{
//if status is inactive, call Activate()
ActivateIfInactive();
//process the subgoals
m_iStatus = ProcessSubgoals();
ReactivateIfFailed();
return m_iStatus;
}
I’m not going to go into the details of Goal_HuntTarget and Goal_Dodge
-
SideToSide
. It’s pretty obvious what they do and you can always examine
the source code if you want to look at the nitty-gritty.
Goal-Driven Agent Behavior | 397
Examples of Goals Used by Raven Bots

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