|
A
common problem for game AI programmers is how to distinguish the
behavior of different AI characters. As an example, how do we make
an orc and a dragon genuinely different as opponents? We can increase
the health, armor, and damage of the dragon, but unless we give
it a different personality in some way, and make it behave differently,
it might as well just be a very strong orc.
The
techniques described in this article are applicable to a wide variety
of game types. I have applied (and refined) them over the course
of developing a console FPS (Men in Black: Crashdown), a
PC and console board game (Monopoly Party), and now a PC
and console, real-time, turn-based, strategy/action game (Worms
3D). The specific methods described are most applicable to games
which have a variety of different kinds of AI agents. The most obvious
examples of games requiring agents with differing behaviors are
probably RPGs, with various races of enemies, or character classes;
and FPSs with various species/types of opponent.
This
article will present a flexible, robust, and easily extensible solution
to the problem of how to give your AI agents a rich palette of behaviors,
as well as a sense of character and personality.
Same
Code, Different Data
A
much-discussed concept in game programming is writing systems to
be "data-driven" (see references at the end of the article),
and this is a perfect place to put the concept into practice. Essentially
the idea is to program your system to work according to data fed
into it, so that the same code can produce very different results
by changing the parameters it is given. The advantage of coding
this way is that program behavior can be changed without altering
the code at all -- by simply altering the data it is fed. This means
that agent behaviors can be tweaked, or even completely changed
or created, without having to edit and recompile code, interrupt
a programmer (it can be done by a level designer), or even exiting
from the game, if you include the ability to reload the data the
engine is using on the fly.
The
disadvantages of writing a system to be data driven, instead of
using hard-coded values, is that it will run marginally slower (although
this will be negligible for the systems described in this article),
but that more importantly, you will need to spend a bit longer up
front, designing and coding your system. Even starting from scratch,
if you are writing a game that will have several types of AI characters,
the time you save in the long-run by designing your system to work
in this way will far outweigh the extra time required at the beginning.
(See the sidebar, "Data Format", for a discussion regarding
what form your data should be in.) My hope is that this article
should give you a head-start with designing your system, and cut
down the time you'll spend up front.
|
|
Sidebar:
Data Format
An
important question is the format used for the personality
data files. They must be backwardly compatible, so that when
you add a new parameter, it won't invalidate all the currently
existing files. Backwards-compatibility can be implemented
by supplying default values for any new parameter. If the
parameter is not explicitly mentioned in a data file, the
default value is used. It may also be useful to allow data
files to inherit from other data files, and then override
the specific parameters which need to be different for the
new character.
I
would advise a text-based, human-readable format for development
(as an aid to debugging). If the time taken to parse these
files is found to be significant, a release version can be
provided with the files pre-processed to reduce the time needed
to use them on the fly. The data files should certainly be
kept in your version control system, as well as your source
code.
In
the examples I have used a simple "token
= value" syntax, with "START
block ... END block" as block delimiters, although
other schemes could of course be used, such as XML. It can
be an advantage to provide a tool to edit these data files.
Such a tool could provide drop-down lists of all animations
applicable to the specified mesh, or of all possible behaviors,
or it could include a "wizard" that fills in all
the parameters with their default values for a behavior when
it is added. Naturally, if others are going to be editing
data files, it will be advisable to provide some documentation--at
least detailing the uses of the different parameters and their
valid range of values.
|
 |
 |
 |
|
An
important thing to realize about data-driving is that well chosen
parameters can combine in unexpected ways to give greater variety
than was originally visualized. In other words, if you give the
power to get your code to do different things to other people, then
they will find ways of making it do things you never intended it
to do. This can be bad -- it will certainly expose some bugs in
your code -- but it can also be very good, as a flexible enough
system will allow the designers feeding your system with data to
exercise their imaginations, without being limited by yours.
But
a dragon and an orc shouldn't just have different health and armor;
they should behave differently. Of course, in a full-blown game
orcs and dragons will have different models, animations, visual
effects, sound effects, rewards for defeating them, and so-on,
but if a dragon just behaves like a very tough orc, the game world
will inevitably feel flat and artificial. Encountering the two
types of opponents should be very different experiences, and should
require very different kinds of response from the player.
Asset
Parameters
The
next aspect of most AI characters that we'll consider has already
been mentioned in Example 2, namely its
weaponry. Most AI characters in games have weapons of some sort,
except of course those guys who like hanging around in taverns
or star-ports, even if it might be a claw or psion-blast, instead
of a gun or axe. Naturally then, we'll want parameters for the
weapons an agent has. The first ones you'll think of are probably
"damage", "range", "accuracy", and
maybe "time between hits", but for a full-blown game
you'll want to include a lot more. The weapon may have a separate
model made for it (if that kind of agent can use more than one
weapon), in which case you'll want to include the name of the
weapon model as one of your parameters rather than having a big
hard-coded switch statement somewhere saying which weapon model
each character uses. But don't stop there. How about having parameters
for the animation to be played when firing the weapon, and the
name of the particle effect when it is fired, and when it hits?
Don't forget all the sound effects as well.
Maybe
all these extra parameters sound like a lot of hard work? Wouldn't
it be easier to just hard-code the names of the assets in? It certainly
would be easier for a game just using two or three kinds of characters,
but if you want to have more, and you want others to be involved
in creating them (which will probably improve your game in the long-run),
then it will save huge amounts of time to encode all this information
into your data file. If you do, then someone else will be able to
add a weapon, with all the graphical and audio assets, without ever
bothering you.
Obviously
you'll want to have the details of all the assets (models, animations,
sound effects, particle effects, etc.) for the actual agent included
in the data file too. Strictly speaking, these sort of things aren't
part of the AI, but it certainly makes sense to put them all together
from the point of view of game content creation. Before long you'll
be playing the game against AI opponents that you've never seen
before, and had no immediate hand in creating, even though they're
using your code. If your design teams are talented and can get to
grips with the tools you provide them with, this can be a very exciting
prospect.
______________________________________________________
|