![]() ![]() |
Artificial Intelligence in games is slowly getting better. With the advent of games like HalfLife and Unreal, even the notoriously dumb AI-engines in first-person shooters are gradually getting more and more intelligent! Is it due to neglect that games have taken so long to get half-intelligent enemies? Perhaps, but it is also due to the incredible complexity of advanced AI engines that has put a lot of programming groups off putting in the effort and research to create one. This essay deals with the techniques often used in AI-engines in games, and possible uses for other paradigms in AI.
| Glossary |
|
• A* Pathing Algorithm • Finite State Machines • Minimax |
Quake2 is a good example to look at since most people have played it. Quake2 uses 9 different states: standing, walking, running, dodging, attacking, melee, seeing the enemy, idle and searching. For the programmers, here is a bit of code from Quake2 that shows how the monsters check whether they should change to their dodge state:
static void check_dodge (edict_t *self, vec3_t start, vec3_t dir, int speed) {
vec3_t end;
vec3_t v;
trace_t tr;
float eta;
VectorMA (start, 6144, dir, end); // JM: Lengthened vector.
tr = gi.trace (start, NULL, NULL, end, self, MASK_SHOT);
if ((tr.ent) && (tr.ent->svflags & SVF_MONSTER) && (tr.ent->health > 0)
&& (tr.ent->monsterinfo.dodge) && infront(tr.ent, self)) {
VectorSubtract (tr.endpos, start, v);
eta = (VectorLength(v) - tr.ent->maxs[0]) / speed;
tr.ent->monsterinfo.dodge (tr.ent, self, eta);
}
}
Note that this comes from a Quake2 mod I created, so I've changed the code slightly. The states in a game might be connected together to form action, for example, to attack in Quake2, the states go from IDLE to RUN (to a point closer to the player), then once the point has been reached, the state switches to ATTACK. The states in a game can often be represented by a simple flow diagram. A typical FSM operation diagram might look like this:
There is also a slight derivative to the state-based engine, but it used in more complicated games like flight simulators and games like MechWarrior. They use goal-based engines - each entity within the game is assigned a certain goal, be it 'protect base', 'attack bridge', 'fly in circles'. As the game world changes, so do the goals of the various entities.
Games like chess, checker, Pente, and Go require a great deal of thinking ahead, predicting what moves the opponent might pick, and how to counter them. This is where minimax trees come in — the goal of a minimax tree is to minimize the opponents maximum move.
A board can be represented as a huge tree of moves, starting with a blank board as the root, then branching off with all the possible first moves, all of which in turn branch, until a winning state (or draw) is achieved. Yet, creating an entire tree of ALL moves would be impossible on current computer - even a simple game could require around a million nodes. So games like chess and Go are definitely impossible to represent as a complete tree. Therefore, the algorithms only generate trees 5-10 layers deep.
Looking ahead obviously uses the assumption that the computer and its opponent use the same set of heuristics (rules) to determine which move to make. This is obviously a rather tenuous assumption to make, especially when playing against humans (therefore, it is often these heuristics that make or break an AI engine). So, the computer generates all possible board positions from the current one and does this for about 5-10 moves ahead. After that, it sets about evaluating the nodes, and assigning values to them according to the "decency" of the move (again, the heuristic involved in this process can have a huge impact on the game). It then uses these values to determine which path to take so as to minimize its opponents best game.
Just as real trees can grow out of control and need to be pruned, so do minimax trees! Even when only evaluating a few moves ahead, in a complicated board game such as chess, these trees can be immense, and take a long time to generate and evaluate. Therefore, pruning is used to ensure time isn't wasted on evaluated pointless nodes.
Last Updated: 29/06/2000