diary of an indie game developer

 

Modern Game AI Basics (… from 2005)

In a recent discussion of game AI, someone helpfully pointed out an article from Damian Isla on the Halo 2 AI.

Despite being from 2005, the article’s still remarkably relevant (but that’s another post).  I highly recommend you read it if you’re into game AI, but it’ll require a bit of time.  It’s a solid rundown on the contemporary AI toolbox.  (It doesn’t discuss more rarely used models such as Fear’s GOAP.)

The basic approach is a “behavior tree” (actually a directed acyclic graph).  Each node consists of a list of potential behaviors, with a decision-making mechanism to choose between them.  Leaf nodes carry out the actual behavior.

The primary decision-making algorithm is the prioritized list.  Basically, you list a few behaviors in order, say: flee, fight, chill.  And then you ask them: “hey, do you want to flee?  No?  Okay, do you want to fight?  No?  Okay, then chill.”  If flee had answered yes, then you’d stop right there, and you wouldn’t ask fight.

I prefer this to another algorithm, the scoring mechanism.  Or, as the article puts it:

Numerous systems feature an analog activation desire: each child provides a floating point number indicating its relevancy, and the child with the highest relevancy wins (with the previous tick’s winner given an added bonus to avoid dithering).

The article mostly discards this option, but I’d like to go into a bit more depth.

I’ve given up on scoring systems for anything other than weighting random selection.  It’s far too easy to accidentally make value judgments.  The idea that you’re going to know every possible scoring of every competing behavior is unrealistic.  So you end up intentionally making the judgment “moving to melee range is more important than ranged against enemy X, but less important than fleeing”, but you end up also ranking your “moving to melee range” behavior against your “get in the vehicle” behavior, or more likely your “get in the vehicle when there’s driver X /Y / Z / no driver / the vehicle is on fire / you’re close to the vehicle / you’re far from the vehicle / the turret is unmanned ” behavior.

Still, I find scoring useful for weighting randomized behavior selection, but I’m unsatisfied with how I usually compute the scoring values when using it for that purpose.

Basic randomization example: you’ve decided that you’re going to perform a melee attack, but you’re thinking about which one.  The opponent is blocking, so a block-breaker is of higher value than normal, and a blockable melee is a bit lower value.

The weighting factor for that is still a black box.  ”Hey, heavy attack behavior: on a scale of 0-1, how valid are you?”  ”Uh… 0.5?”  ”Hey, standard weapon attack: how about you?”  ”Um… 0.7?”  You could restrict the return values to a descriptive enum, say, “awesome, standard, crappy, or invalid”, which each scale the score by a predefined amount, and make it easier for designers to control.  It still seems like an inelegant hack, and I’m open to suggestions.

Returning to the article, it goes into a lot of cool ways to make your prioritized lists more dynamic.  For instance, a Halo 2 squad seeing its leader get killed will cause a high-priority flee action to get inserted into one of the behavior tree nodes for several seconds, potentially causing the squad to run like hell.

An important note: I enjoyed Halo’s enemy AI, but not necessarily because it was substantially better than in competing games.  Halo did a great job of communicating what its AI was doing, through animation and voice cues.  Your AI’s awesomeness doesn’t matter if the player can’t tell what’s happening.

blog comments powered by Disqus