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

NPC will endlessly loop through its patrol points until instructed otherwise.
See Figure 9.15.
Very shortly after this innovation, it was realized that not only could
position vectors be queued, but so could any type of command. Subse
-
quently, rather than issuing only one order at a time, by simply holding
down a key while selecting orders, the player could queue multiple com
-
mands. For example, an NPC can be instructed to collect some gold, then
build a barracks, then attack an enemy unit. Once the orders are issued the
player can focus his attention elsewhere, confident the NPC will follow
orders.
Command queuing significantly reduces the amount of time a player has
to spend on micromanagement and increases the time available for more
enjoyable aspects of the game. It therefore has become an indispensable
feature within the RTS genre. Fortunately, using the composite goal archi
-
tecture, this sort of functionality is incredibly easy to implement. All you
have to do is allow clients to add goals to the rear of the subgoal list in
addition to the front. That’s it! Five minutes of work and you get command
queuing.
You can observe command queuing in action in Raven. Unfortunately,
unlike an RTS, Raven does not have lots of interesting commands, but you
can queue multiple MoveToPosition goals by holding down the “Q” key
while clicking on the map. I implemented this by adding the
QueueGoal_
MoveToPosition
method to Goal_Think and some additional code for calling
that method if the player clicks on the map while holding down the appro-
priate key. If you release the “Q” key and right-click on the map again, the
queue is cleared and replaced with the single new goal. This would be just
as easy to implement with any goal of your choosing though, because the
queuing takes care of itself.
Using the Queue to Script Behavior
Another benefit of turning the subgoal list into a queue is that it enables
you to script linear action sequences without too much difficulty. For
example, you can create behavior like the following:
n
A player enters a room and a ghostly game character appears that
floats to a chest positioned in the corner, opens the chest, takes out a
scroll, floats back to the player, and hands him the scroll.
n
A player enters a hotel lobby with a glass ceiling. After a brief time
spent in the room, a helicopter is heard. Seconds later the ceiling
shatters into a million shards and several armed men in black are
seen rappelling from the helicopter. When they hit the floor they
scatter, each finding cover in a separate location, and start firing at
the player.
412 | Chapter 9
Spin-offs
n
A player finds an old brass lamp. He rubs it and a genie appears. The
genie says “Follow me” and leads the player to the opening to a
secret tunnel, where it promptly vanishes in a puff of smoke.
To do this you have to ensure you define a goal for each step of the
sequence and the triggers required to activate the script. In addition, you
have to expose the relevant C++ code to your scripting language.
For example, to script the third example from the previous list in Lua
you’d need to complete these tasks.
1. Create three goals:
n
A SayPhrase goal, which would output some text to the screen for
a specified amount of time.
n
A LeadPlayerToPosition goal. This is similar to the MoveTo
-
Position goal seen in Raven except it has additional logic for mak
-
ing sure the genie does not lose sight of the player while leading
him to the secret tunnel.
n
A VanishInPuffOfSmoke goal, which would remove the instance
of the genie from the game world and leave behind a puff of
smoke.
2. Create a trigger that is activated when a player performs the “rub”
action on a specific “lamp” object. When activated, the trigger should
call the appropriate Lua function.
3. Expose the relevant parts of the game architecture to Lua. Ideally
you’d like to write a script that looks a little like this:
function AddGenieTourGuide(LampPos, TunnelPos, Player)
--create an instance of a genie at the position of the lamp
genie = CreateGenie(LampPos)
--first welcome the player, text stays on screen for 2 seconds
genie:SayPhrase("Welcome oh great "..Player:GetName().. "!", 2)
--order the player to follow the genie. text stays on screen for
--3 seconds
genie:SayPhrase("Follow me for your three wishes", 3)
--lead the player to the tunnel entrance
genie:LeadPlayerToPosition(Player, TunnelPos)
--vanish
genie:VanishInPuffOfSmoke
end
Therefore you need to expose a C++ method that creates a genie, adds it to
the game world, and returns a pointer to it, along with methods for adding
the appropriate goals to a genie’s goal queue.
Goal-Driven Agent Behavior | 413
Spin-offs

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