It’s clear that developing AI for a modern game is a challenging undertaking. Our games have become increasingly complex in terms of their environments, in terms of the depth of their story, and in terms of the gameplay itself. Players have become more discriminating, widespread multiplay has offered them an alternative to playing against the computer, and their expectations have been raised by other games that successfully delivered compelling AI. Worse, when a game provides compelling AI in a limited domain, even at the expense of other features, it raises the bar for the entire industry. Improvements in graphics and animations have allowed us to approach photorealism, simultaneously causing players to expect a similar level of behavioral fidelity and chewing up processor resources that are needed for many generic AI techniques. And at the end of the day, most game AI is still done using a procedural, rather than a declarative, approach (for a discussion of the relative merits of procedural vs. declarative AI, see my article in AI Game Programming Wisdom 4).
At the same time, despite the difficulty and expense of creating game AI, we continue to throw all of that work away at the end of each project, and start fresh for the next game. Sure, we may retain a few tools – a scripting language here, a behavior tree architecture there – but the bulk of the work, the actual behavior, is tossed on the scrap pile.
Code reuse has been applied successfully in other areas of game development. We don’t typically build a new renderer for each game. We don’t typically reinvent our physics engine, or change the code that controls animation in any fundamental way. Sure, we’ll extend what we’ve got, add new features – maybe better water effects, maybe a new blending technique that allows us to generate better facial animation – but I would argue that the fact that we retain the bulk of our old code is precisely what allows us the freedom to really dig into the areas that provide the most bang for the buck. We’d never have time to focus down on getting the God rays, ripple distortion, and the atmospheric particle effects when swimming underwater looking just right, for example, if we had to rebuild the renderer from the ground up each time we built a game.
What’s more, there are middleware companies that have been building libraries of reusable code for years – building a solid product, whether it is a renderer or a facial animation system or just a tool for making really good looking trees – and then iterating and improving on it while continuing to sell it for use in hundreds of games.
My article in Game Programming Gems 8 discussed one potential approach to code reuse for Game AI, but here I’d like to discuss a different (although perhaps complimentary) approach. The insight driving this approach is that while there is AI middleware as well, generally speaking, with the exception of path-planning middleware, it hasn’t really taken off. It seems to me that one of the reasons it hasn’t taken off is that it’s providing code reuse at the wrong level of granularity. What you get with most of the AI middleware packages is a development environment in which you can build your behavior. In other words, you get a fairly standard reasoning architecture (typically either an HFSM or rule-based architecture) plus some tools. The problem is that building the reasoning architecture is really only about 20% of the job. The other 80% - the hard 80%, the 80% that requires endless iteration and polish, the 80% where your AI succeeds or fails – is using that architecture to create the actual behavior for your characters. What we need
On a side note, as I mentioned above, one area in which AI middleware companies have succeeded is path planning – a domain where they’re controlling behavior, not just providing tools for specifying it. A subtle difference, perhaps, but an important one.
So why aren’t we reusing AI behavior? It seems to me that it boils down to two reasons. First is the perception that AI behavior is extremely game specific. That there’s so much that is unique about each game that it’s impossible (or at least inadvisable) to share behavior between games. Even for two very similar games (say, for instance, two WWII first-person shooter games), it is essential to customize the behavior for each game, to give each game the unique feel that is what makes it cool.
The second problem is that it’s not clear that we know how to do this behavior sharing. What would we be saving? Finite states? Behavior subtrees? How would the game interface with those objects, and how would they interface back into the game?
So let’s take both of those problems in order. First, the issue that each game is a delicate flower, pure and perfect, and wholly unique from every other game that’s ever been made. Honestly, that’s bullsh… erm, I mean, I respectfully disagree.
So as random examples, let’s take the last two games I worked on. The most recent was Red Dead Redemption. This game was not a standard space-marine-fighting-demons Doom-style shooter. It was set in the early 1900s, with era-appropriate weapons. Nevertheless, it had characters armed with pistols, rifles, shotguns, grenades-like weapons, and occasionally even machine guns. The various weapons had variations in how much damage they delivered, optimum range, rates of fire, and so forth. The characters could do things like fire, duck behind cover, and reload. There were first aid kits that would restore your health. Common team tactics such as using suppressive fire and flanking an opponent were viable (though not necessarily used by the AI). Any of this sound familiar?
The game I worked on before that was Iron Man. Again, this was not a standard FPS – in fact, it was quite a bit more of a departure than Red Dead. Nevertheless, the vast majority of characters had weapons like missile launchers, machine guns, or rifles. They could use cover. They could reload. They could use team tactics.
Both games focused on things other than high quality AI opponents for tactical combat, and honestly both struggled during development to create good combat behaviors for their characters. That’s not to say that the end result wasn’t good – I’m proud of the result in both cases – but significant time and money could have been saved during development if we’d had an existing library of FPS behaviors as a starting point. What’s more, having that library would have allowed us to spend our time polishing and tuning the behaviors we wanted specifically for that game, rather than reinventing behavior that has been commonplace for years. I think this is the most important point. Having reusable behavior would not decrease your ability to customize and tune the behavior in a game, it would increase it. The time normally spent rebuilding basic functionality could instead be spent on customization. Those resources could be dedicated to the aspects of the game which make it unique, rather than being expended on aspects of the game that are, honestly, fairly generic.
The ability to find a common core of behavior isn’t unique to shooters. How many strategy games have a handful of resources, a rock-paper-scissors approach to combat, and technologies that improve the units in fairly similar ways? How many fantasy RPGs have tanks, healers, and DPS? How many games have background characters that just need to act in generic and believable ways? Again, the details aren’t the same from game to game, but the general shape of the problem is. A general solution could, in theory, get us 80% of the way there, and let us focus on the last 20%, rather than spending all of our time rebuilding that first 80% - or worse, the first 60%.
This brings us to the second problem. It does us no good simply to *want* to reuse behavior. We also need to *be able* to do so. Despite a decade of attempting to do so, we have not yet agreed on common standards for game AI. There is no equivalent to the texture-mapped triangle, or the animation skeleton, that we can rely on being the same in every game ever built. What’s more, there’s no evidence that there will be a general solution to that problem any time soon. Game AI is just not something that lends itself to standardized solutions.
With that said, the general shape of an AI is pretty standard. The AI accepts data from the outside environment – often called “sensing.” It then processes that data – often called “thinking” – and selects one or more things to do – often called “acting.” My suggestion would be to share the entire core of the AI – the “thinking” part – and provide interfaces to the game engine which specify what the AI expects to see on the sensing and the acting side.
As an example, on the sensing side our shooter AI would want to know things like the position of the character, its enemies, and its allies. The position and size of any cover locations. The priority for taking down each enemy, and for protecting each ally. The weapons it has to choose from, their ranges and damage characteristics, magazine capacity and current load, and the amount of ammunition available. It could then process that information and return actions such as “crawl to this position,” “shoot at this target,” or “reload your weapon.”
The end result is a core set of behaviors which, while genre-specific, would still be applicable in a great many games. For instance, the combat AI that I described above could not only be used in most FPS games, but also many RPGs, and even to control individual units in some RTS games. In order to reuse the behavior you’d first implement the wrapper which handles interfacing the sensing and acting steps to the game code, and then you’d go into the core of the AI and tune the existing behaviors to match your creative vision.
Shooter AI is one extremely common area in which reusability could work for us, but it isn’t the only one. A similar approach could be taken for high-level strategy AI, for sports games, for the background characters that fill out the world, or for any other area that seems widespread enough to be worth the effort.
Of course, all of that is easier said than done. The key challenges seem to be:
* Building a core set of behaviors which provide the basic functionality that’s desired in a large set of games. Obviously this behavior set will grow and change over time, but we need to start by getting the basics implemented.
* Providing the means to add and remove behaviors for specific games, as well as the means to tune the decision making process used to select those behaviors.
* Similarly, providing the ability to add and remove sensor data and actions from the external interface so as to be able to customize the AI for each game.
Put that way, this seems like a large but solvable problem. Sure there’s significant work there – but there was significant work to build shared libraries for physics, or for rendering, or for network code as well. And once that work is accomplished, hopefully we can get over the hump of constantly reimplementing the basics, and on to the challenges of achieving behavioral photorealism.