Artificial Intelligence
Overview
Some of my earliest memories are of my dad bouncing me on his knee, playing computer games on our 8088. I was fascinated with computers, despite the fact that we only had two games for the machine: a game where a donkey ran down the road avoiding cars, and an app that used the PC speaker to crudely simulate a piano. One of my first phrases was "Dunkee n musik," a jumbled group of syllables I would yelp when I wanted to play the games.
Right around then was when I saw my first AI application. The title escapes me (I believe it may have been just Animal), but the premise was simple enough. The object of the game was for the computer to guess an animal you were thinking about. It would ask a series of yes/no questions that would narrow down the possible choices (examples would be "does your animal fly?" or "does your animal have four legs?"), and when it was sure, it would tell you what it thought your animal was. The neat thing was, if it didn't guess your animal, it would ask you for a question that differentiated the two animals, something your animal had that the other didn't. From then on, the program would be able to guess your animal! It could learn!
This impressed my young mind to no end. After some formal training in programming, I've come to accept that it's a fairly trivial program: The application keeps an internal binary tree with a question at each branch and an animal at each leaf. It descends down the tree asking the question at each branch and taking the appropriate direction. If it reaches a leaf and the animal stored there isn't yours, it creates a new branch, adds your question, and puts your animal and the animal previously in the leaf in two new leaves.
How the program worked, however, really isn't that important. The trick is, it seemed intelligent to me. Game programmers need to aim for this. While academia argues for the next 50 years over whether or not human-level intelligence is possible with computers, game developers need only be concerned with tricking humans into thinking what they're playing against is intelligent. And luckily (for both developers and academia), humans aren't that smart.
This is, of course, not as easy as it sounds. Video games are rife with pretty stupid computer opponents. Early first-person shooters had enemies that walked towards the player in a zigzag pattern, never walking directly towards their target, shooting intermittently. Bad guys in other games would sometimes walk into a corner looking for you, determined that they would eventually find you even though you were several rooms away. Fighting games are even worse. The AI governing computer opponents can become extremely repetitive (so that every time you jump towards the opponent, they execute the same move). I can't promise to teach you everything you need to know to make the next Reaper Bot; that would be the topic of an entire book all its own. By the end of this chapter, however, you should be able to write an AI that can at least challenge you and maybe even surprise you!
Starting Point
Most AI problems that programmers face fall into three groups. At the lowest level is the problem of physical movement-how to move the unit, how to turn, how to walk, etc. This group is sometimes called locomotion, or motor skills. Moving up one level is a higher-level view of unit movement, where the unit has to decide how to get from point A to point B, avoiding obstacles and/or other units. This group is called steering, or task generation. Finally, at the highest level, the meatiest part of AI, is the actual thinking. Any cockroach can turn in a circle and do its best to avoid basic obstacles (like a human's foot). That does not make the cockroach intelligent. The third and highest stage is where the unit decides what to do and uses its ability to move around and plan directions to carry out its wishes. This highest level is called motivation, or action steering.
Locomotion
Locomotion, depending on how you look at it, is either trivial or trivially complex. An animation-based system can handle locomotion pretty easily, move forward one unit, and use the next frame of animation in the walk cycle. Every game on the market uses something similar to this to handle AI locomotion.
However, that isn't the whole story. When you walk up stairs, you need a stair walking animation; when you descend down a hill, you naturally lean back to retain your balance. The angle you lean back is dependent on the angle of the hill. The amount you dig your feet into the ice is dependent on how slippery the ice is and how sure your footing needs to be before you proceed. Animation systems robust enough to handle cases like this require a lot of special casing and scripting; most animation systems use the same walk animation for all cases. I always found it kind of disappointing when the guards in the surface level of Goldeneye could simply walk up 8-foot tall, 70 degree banks of snow.
A branch of control theory attempts to solve this with physical controllers. You can actually teach an AI how to stand and tell it how to retain its balance, how to walk around, jump, anything. This gives the AI incredible control, as the algorithms can handle any realistic terrain, any conditions. Many people agree that the future of locomotion in games is physical controllers.
However, physical controllers aren't easy. At all. For these purposes, it's total overkill. As Moore's law inevitably marches forward, there will eventually be enough processing power to devote the cycles to letting each creature figure out how to run towards its target. When this happens, games will be one huge step closer to looking like real life.
Steering-Basic Algorithms
Even games with little or no AI at all need to implement some form of steering. Steering allows entities to navigate around the world they exist in. Without it, enemies would just sit there with a rather blank look in their eyes. There are a slew of extremely basic steering algorithms that I'll touch upon, and a couple of slightly more advanced ones that I'll dig into a little deeper.
Chasing
The first AI that most people implement is the ruthless, unthinking, unrelenting Terminator AI. The creature never thinks about rest, about getting health or ammo, about attacking other targets, or even walking around obstacles: It just picks a target and moves towards it each frame relentlessly. The code to handle this sort of AI is trivial. Each frame, the creature takes the position of its target, generates a vector to it, and moves along the vector a fixed amount (the amount is the speed of the creature). Pseudocode to handle this type of AI is in Listing 6.1.
Listing 6.1: The Terminator manifested
void cCreature::Chase( cObject* target )
{
// Find the locations of the creature and its target.
point3 creatureLoc = m_loc;
point3 targetLoc = target->GetLoc();
// Generate a direction vector between the objects
point3 direction = targetLoc - creatureLoc;
// Normalize the direction (make it unit-length)
direction.Normalize();
// move our object along the direction vector some fixed amount
m_loc += direction * m_speed;
}
Evading
The inverse of a chasing algorithm is what I could probably get away with calling rabbit AI, but I'll leave it at evading. Each frame, you move directly away from a target as fast as you can (although in this case the target would most likely be a predator).
Listing 6.2: John Connor, perhaps?
void cCreature::Evade( cObject* target )
{
// Find the locations of the creature and its target.
point3 creatureLoc = m_loc;
point3 targetLoc = target->GetLoc();
// Generate a direction vector between the objects
point3 direction = targetLoc - creatureLoc;
// Normalize the direction (make it unit-length)
direction.Normalize();
// move our object away from the target by multiplying
// by a negative speed
m_loc += direction * -m_speed;
}
Pattern-based AI
Another fairly simple AI algorithm I'm going to discuss is pattern-based AI. If you have ever played the classic Space Invaders, you're familiar with this AI algorithm. Aliens take turns dive-bombing the player, with every type of alien attacking in one uniform way. The way it attacks is called a pattern. At each point in time, each creature in the simulation is following some sort of pattern.
The motivation engine (in this case, usually a random number generator) decides from a fixed set of patterns to perform. Each pattern encodes a series of movements to be carried out each frame. Following the Space Invaders theme, examples of pattern-based AI would be moving back and forth, diving, and diving while shooting. Anyone who has played the game has noticed that each unit type dives towards the player the same way, oblivious to where the player is. When the baddies aren't diving, they all slide back and forth in the same exact way. They're all following the same set of patterns.
The algorithm to run a pattern-based AI creature is straightforward. I'll define a pattern to be an array of points that define direction vectors for each frame of the pattern. Since the arrays can be of any length, I also keep track of the length of the array. Then during the AI simulation step the creature moves itself by the amount in the current index of the array. When it reaches the end of an array, it randomly selects a new pattern. Let's examine some pseudocode to handle pattern-based AI.
Listing 6.3: Pattern-based AI
struct sPattern
{
int patternLength;
point3 *pattern; // array of length patternLength
};
sPattern g_patterns[ NUM_PATTERNS ];
void cCreature::FollowPattern()
{
// pattFrame is the current frame of the pattern
// pattNum is the current pattern we're using.
if( pattFrame >= g_patterns[ pattNum ].patternLength )
{
// new pattern
pattNum = rand()%NUM_PATTERNS;
pattFrame = 0;
}
// follow our current pattern.
m_loc += g_patterns[pattNum].pattern[pattFrame++];
}
Pattern-based AI can be specialized into what is known as scripted AI. When a certain state is reached, the motivation engine can run a certain scripted steering pattern. For example, an important state would be your player entering a room with a bad guy in it. This could cause the creature to follow a specialized animation just for that one game situation. The bad guy could run and trip an alarm, dive out of bed towards his bludgeoning weapon of choice, or anything else you can dream up.




Rispondi Citando















