DodgeBall
It’s the essence of DodgeBall.
Although visually inspired by classic Pong, today’s Game-a-Day takes place with four balls inside a conceptual school gymnasium. See, a school gymnasium:

Of course.
The opponent player demonstrates a few rudimentary videogame AI design principles. Getting 1-on-1 DodgeBall to play and feel “right” using only mouse position and 1 button made for a by-the-book fit for context-sensitive action. These are the two details that I’m going to dig into for today’s post.
In creating the AI opponent I had 3 design goals:
- If a player can’t do it, the AI should never do it.
- If a player would do it, the AI should always do it.
- Some of the time, the AI should make the types of mistakes that players make.
Goal #1, disallow cheating, was easy. It translates to not letting the AI move any faster than the player can move, not letting it throw faster than the player can throw, and not using information it shouldn’t have access to (ex. player’s mouse position before clicking; you can’t see where it’s thinking of moving/throwing next, right?). This problem is solved by writing AI that uses the same underlying machinery. In tech terms, it is an identical instance of the player’s class, except there there’s a single AI() function calling other internals (MoveTo, ThrowAt) based on the world state instead of letting an Input() function call those operations as it does for the player.
Goal #2, doing what a player would do, is also straightforward in this universe. It amounts to asking, “W.W.P.D.”, or What Would a Player Do. This includes details like the following, written from the AI’s perspective:
- If an enemy thrown ball is on my side, I should move away from it, and back up toward the wall in case more balls are coming.
- If I am standing on a ball, I should throw it at the player.
- If a ball is at rest on my side, I should move to it.
- If no balls are on my side, I should back up toward back wall where there’s more time to react to a player throw.
Each one of those is conceived as an answer to a multi-part question: (A.) systematically, how do I identify the problem that warrents reaction (B.) operationally, what command could I use to drive the desired reaction (C.) in terms of behavioral design, with what priority should this decision be made to override other potentially conflicting decisions? The above is listed in the form of if A, then B, listed from most to least important as an answer to C.
Goal #3 - fall for tricks “some of the time” - is mildly tricky in this case, since I don’t want to mess with AI memory across time. Trying to write code to drive decisions like “let that ball hit me this time” is tricky to debug, and is likely to come across as extremely artificial in many common cases: stand there and pretend the incoming ball isn’t noticed? Force “realistic looking” ways to fake human error patterns? Yuck!
So instead, my solution to Goal #3 was to make the relationship between the top priority (dodge balls) and the other top priorities (move to and throw balls) systematically inconsistent. In memory, the balls exist as 4 entries in a numbered set, so that one ball is “Ball 0″, one is “Ball 1″, another is “Ball 2″, and the last is “Ball 3″. Priority action goes to whichever ball on the enemy’s side of the court has a lower number in that set. This results in behavior that will, half of the time, prioritize offense over defense, which models the selective attention and decision making that will get a human player hit - a human will often dart for another ball to throw, and get hit from focusing only on that ball.
Because the balls all look identical on the field, it’s tricky to exploit this system. The enemy player just winds up playing slightly more aggressively 1/2 the time. If it always prioritized cowering in the corner, the games could go on for a very long time, and the player could easily manipulate the enemy by pinning it into a corner with consecutive shots. Instead, when multiple balls are thrown consecutively, it’s impossible to know in advance exactly how the opponent will respond to them.
Ta da! That’s how I put together the stateless AI that doesn’t cheat, behaves “like it should,” and makes systematic oversights similar to the ones that human players make. All that only took about 20 lines of code.
The importance of that third ingredient - minor inconsistency and ability to focus its attention on the wrong thing - makes it so that the player can outsmart the AI (which rewards players for building and acting upon a mental model), and also helps the AI feel more human, instead of coming across as a byproduct of deterministic computation.
Smart AI is not necessarily better for videogames. There’s an elegance and simplicity behind why so many games over the past 30 years have had robots, zombies, ogres, ghosts, mutants, and giant insects. Although initially these concepts helped developers hide the fact that it’s all their technology could support, any more it occurs because these are types of enemies that (A.) players don’t feel conflicted about killing (B.) it’s reasonable for them to take multiple hits before dying without breaking stride (and C. - the AI point) they are not expected to act intelligently, yielding systematic behavior that a player can learn to outsmart.
In an action game, “Realistic” AI would be silent and out of sight until you were dead. “Realistic” AI would retreat and call for reinforcements until there was no question about their ability to collectively bring you down, particularly after you just killed their buddy. “Realistic” AI would get shot once, be severely disabled, and either scramble in an effort to hurt you anyway or start negotiating for you to spare its life. These things sound unfun, hopeless, and sick, respectively, and have no place in games that I’m interested in playing or making.
Anyhow, to return to DodgeBall. This game uses context-sensitive action, or CSA, which in interface design refers to a single button serving different mutually exclusive purposes based on the context in which it is used. This commonly appears in games where a single “action” button opens doors, throws switches, mounts ladders, grabs enemies, or even reloads based on the player’s relationship to the other elements of the world. In developing Trichromic, a freeware Game Creation Society game, we used CSA to avoid menus when clicking on things; moving, attacking, loading APCs, capturing buildings, and many other actions were simply driven by one mouse click, based on what you clicked on. In this case, since I’m aiming to only use 1 mouse button (to be Mac friendly) and no keyboard (to keep things simple), I had to turn to CSA since the game requires throwing, dodging, and picking up balls.
My approach was to simplify the problem space, then segment what was left. If a ball can be picked up, then can a ball be put back down? If a player holds a ball and clicks on his/her side of the court, is the intention to move there, to place the ball in that spot for use later? Because this presented a dead end of user intentionality, I nixed the case altogether, and instead of picking up or putting down balls, the player can only throw a ball from where it’s placed. Conceptually, standing in a way that touches a ball “picks it up” and moving to a new position “puts it back down”, even though the proximity to a ball on the floor isn’t really relevant until the player attempts to throw.
With picking up the ball no longer in the equation, now I only had to worry about throwing and moving. If the players were on an open field, this would be a very messy problem to solve - if I am standing by a ball (”holding it”) and click someplace, am I trying to move there, or throw the ball there? The metric of whether or not I click on an enemy player is inadequate, because a moving target often needs to be led, which would require clicking in legally traversable space.
“Conveniently” (i.e. that’s why I designed it this way), the player are instead on two mutually exclusive halves of the gym. This means that if I click on one side of the gym, it can only imply movement, and if I click on the enemy’s side, it can only imply throwing. I simply designed the problem out of my decision space.
There remains one more detail to the CSA that hasn’t been addressed. Clicking outside of the play space can be frustrating for the player, and it really isn’t intended to have much relationship to the game. Thus, if a player clicks outside of the left half of the playing field, the player’s avatar will move to the wall closest to where the player clicked. This is not the case with throwing, because the distance clicked from the player affects throw power, and to allow clicking to the far right of the gym would communicate expectation of a super fast throw. In the case of player movement, that the player moves only to the wall and stops is visually communicated; in the case of a throw, how much power it carries is not instantly recognizable, and thus to avoid this confusion I made it illegal/ignored when clicks happen outside the right half of the playing field.
December 17th, 2007 at 6:42 am
I see this game as an example of how sometimes ‘twigging’ the underlying mechanics can ruin a game.
I enjoyed a couple of games, managing to beat the computer on a 2nd turn, but after reading the article and being more conscious of the rules the computer player follows, I fell into a system of ‘meta-gaming’, finding 2 balls that when thrown together would always cause the computer to be hit, then just repeating that move.
I think that such ‘meta-gaming’ can give the whole thing a sense of artifice. Like starting to notice an author’s language or writing ‘tricks’ instead of the story.
In my mind, this is an argument for assymetric 1P games, where folk wouldn’t expect the computer to have the intelligence of a human anyway. E.g. for this game (it may not have been suitable for whatever your intentions were) maybe have X enemies with 1 ‘life’ before they are removed from the game and give us Y lives. Or have us face successive opponents. whatever. By taking away the equality between player/opponent, I think an inequality in the intelligence is more easily overlooked.
December 17th, 2007 at 10:30 am
The game is certainly played a bit differently once you know how to exploit the AI. Of course, if you’re interested in just playing for playing’s sake, it’s entirely possible to go back to playing without using that particular tactic, but point well taken.
“In my mind, this is an argument for assymetric 1P games, where folk wouldn’t expect the computer to have the intelligence of a human anyway.”
Most of my games go this route - often to such an extreme that the enemies might not even be ascribed any degree of “intelligence” in the traditional use of the word. DarkPlace and HotLavaMonkey are two pretty decent examples of this in action, as is NinjaVsPirates. It was nice to work on some slightly more involved AI for one night though.
:)