Homegrown AI

In this section we'll talk about creating your own AI, as opposed to using AI algorithms found elsewhere. The information presented here does not even scratch the surface of learning how to create any AI that's another subject for a much longer, more technical book. Here the information covers a specific AI.


To introduce you to the kind of script we're going to discuss, from the Chapter09 directory on the CD open shark_attack.swf, which should look familiar from Chapter 7, "Tile-Based Worlds." Shark Attack! is an isometric tile-based-world game, with some AI enemies, that I created for a company called Simply Scuba. You are the red fish. The goal is to collect the key and go to the door. Collect coins and objects as you go, for more points. Watch out for the sharks, though; they are the enemies. Double-click the SWF file to open it. Play a few levels (there are only four included) and notice the behavior of the sharks. They are controlled with a fairly simple but effective AI. In this section you will learn how an AI very similar to this was created.


Rules for Controlling Characters


By this point in your odyssey through this book, you are ready to complete this game on your own!

Open run_away.fla in the Chapter09 directory. This file contains the enemy AI for an unfinished game called Grave Robber. Here, we will look at how enemies (also called "baddies") behave. The baddies are zombies, and the good guy (well, as good as a thief can be) is human he is controlled by you. You walk around trying to rob graves, and every time you do, the zombies try to "get" you. There are walls that you cannot pass through. In this file, there is no collision detection between the hero and the baddies, since we are only illustrating behavior. Warning: This file (and in fact every example file we use in this chapter) uses tiles, so if you haven't yet familiarized yourself with tile-based worlds, then you might want to take the time to do so (see Chapter 7). We will only discuss the ActionScript used in the AI for this file, not the world creation or how we handle wall collisions.

Use Test Movie to take a look at this world. Move around and try to notice the behavior of the enemy zombies. The AI used here is very similar to the AI used in the Shark Attack! game.


There is a script within the code that instantaneously changes the direction of the enemy's motion. To be concise, I'll call the running of this script an "update." Now let's look at the rules that the zombies follow in this update to produce their behavior: homing in on the thief.

  • The characters' movement is restricted to horizontal only or vertical only at any given time.

  • The update script checks the hero's location relative to the enemy's, and stores the information as follows:

    Horizontal motion

    1 if the hero is to the left of the enemy

    0 if the hero is in the same column

    1 if the hero is to the right of the enemy

    Vertical motion

    1 if the hero is above

    0 if the hero is in the same row

    1 if the hero is below

  • If the horizontal and vertical values are both 0, then the enemy is in the same tile as the hero, and the update does not change the path of motion.

  • If either horizontal or vertical is 0, then the script changes the direction of motion to have the hero move along the other. For instance, if the horizontal value is 1 and the vertical value is 0, then the script knows that the hero is in the same row to the left, and it makes the enemy move left.

  • If both the horizontal and vertical values are non-zero, then the script randomly chooses one of the two directions and makes the baddy move that way. For instance, if the vertical value is 1 and the horizontal value is 1,then the AI knows the hero is somewhere to the top right of the enemy. It then randomly chooses either vertical or horizontal and moves toward the hero in that direction.

  • The update script contains a randomization condition (in the form of an if statement). At random times the script will choose a completely random direction to move, no matter what the state of the board is. This is the AI's "dumb-down" feature. The frequency of this random "imperfection" makes the AI behave unpredictably.

So now we know the logic that is performed when the update script is executed. But when is it executed? Here are the conditions for which the update script can be executed:

  • When the enemy bumps into a wall or any immovable object.

  • When maxtime number of frames has passed since the last update. The value of maxtime is different for each enemy.

Drawbacks and Solutions


Before we look at the actual ActionScript for bringing this AI to life, I want to mention the drawbacks of this AI. You may notice that the enemies usually stay pretty close to walls. With this behavior, if you had a fairly empty world, then the enemies would tend to stay along the outer edge of the world. This AI works best with worlds that have many walls environments that are almost mazelike. If you mostly like this AI but want to make it more intelligent than the wall-hugging behavior implies, you can do that without too much trouble. Here are some ways you can smarten it up:

  • Program the update to make the character move toward the center of a tile to continue motion rather than hugging up against a wall. This is more of an aesthetic enhancement, but it also gives the appearance of greater intelligence.

  • When a character collides with a wall, give higher priority to turning another direction rather than moving into the wall again. With the current AI you can slam into the wall a few times before moving away. This is not all that noticeable because the collisions happen so fast, but it does happen.

  • Add diagonal motion.

Enemy ActionScript

OK, now it's finally time to look at the ActionScript used in this AI. This function, baddyAI(), is called in every frame. It loops through an array of enemies and determines if it is time for an update. If it is, then it performs the update.

 1    function baddyAI() { 2        for (var i = 0; i<game.baddies.length; ++i) { 3           var ob = game.baddies[i]; 4           ++ob.time; 5           var cell_x = Math.ceil(ob.x/game.cellWidth); 6           var cell_y = Math.ceil(ob.x/game.cellWidth); 7           var cell_over = game.tiles[cell_x][cell_y]; 8           v-ar cell_x_temp =                Math.ceil(ob.tempx/game.cellWidth); 9          var cell_y_temp =               Math.ceil(ob.tempy/game.cellWidth); 10         var cell_over_temp =               game.tiles[cell_x_temp][cell_y_temp]; 11         if (!cell_over_temp.empty               || ob.time == ob.maxtime) { 12             ob.time = 0; 13             ob.maxtime = 30+random(30); 14             ob.tempx = ob.x; 15             ob.tempy = ob.y; 16             var tempDir = ob.dir; 17             var xmov = 0; 18             var ymov = 0; 19             var speed = Math.abs(ob.speed); 20             var xsign = (game.char.x-ob.x)/                 Math.abs((game.char.x-ob.x)); 21             var ysign = (game.char.y-ob.y)/                 Math.abs((game.char.y-ob.y)); 22              if (random(10) == 0) { 23                  var xsign = -1*xsign; 24                  var ysign = -1*ysign; 25              } 26              if (xsign == ysign || xsign == -ysign) { 27                  var ran = random(2); 28                  if (ran == 0) { 29                      var xsign = 0; 30                  } else { 31                      var ysign = 0; 32                  } 33              } 34              if (xsign != 0) { 35                  var ymov = 0; 36                  var xmov = xsign*speed; 37                  if (xmov>0) { 38                      var dir = "right"; 39                  } else { 40                      var dir = "left"; 41                  } 42               } else if (ysign != 0) { 43                   var xmov = 0; 44                   var ymov = ysign*speed; 45                   if (ymov>0) { 46                       var dir = "down"; 47                   } else { 48                       var dir = "up"; 49                   } 50               } 51               ob.dir = dir; 52               ob.clip.gotoAndStop(dir); 53               ob.xmov = xmov; 54               ob.ymov = ymov; 55           } 56       } 57   } 

This is a pretty long function, but don't panic there is a lot of reappearing information. That is mostly because of the several if statements and because everything we do for the x direction we also do for the y direction. As with many of the files created in this book, here we have an object called game that stores information about the game. There is an array called baddies stored in game that contains one object for each enemy ("baddy") in the game. This function loops through the baddies array and checks out each baddy object to determine if it is time to run an update. Line 3 sets a temporary reference called ob to the current enemy that we are inspecting in the baddies array. In the next line we increment the time variable in ob. Remember that one of the conditions to determine if it is time for an update is if maxtime is the same as time. We will perform this check further down (line 11). In lines 5 and 6 we determine which cell the enemy is currently over, and in lines 8 and 9 we determine which cell the enemy would be over at the end of the frame. The cell that the enemy would be over at the end of the frame is given a temporary reference called cell_over_temp. In line 11 we check two conditions to determine if it is time for an update. First, if cell_over_temp is not empty (that is, if it contains an object), then we perform an update. Second, if the time variable is the same as the maxtime variable on the enemy object, then we also do an update.

Let's look at the update (starting in line 12). First we set time back to 0 so that the counter will start over. Next we semi-randomly set a new maxtime value. There is nothing special about the numbers chosen for this randomization. You can change them and get different behaviors of the enemies. If you are interested in repurposing this AI and want some control over its difficulty level, this is one line of code you might want to play around with. In the next two lines we set the enemy's position to where it was at the beginning of the frame (lines 14 and 15). Then we store the current direction of the enemy as tempDir. This is a string value that is "left", "right", "up", or "down". We then set the values of the x and y velocities to 0 so that we can reassign them from scratch (lines 17 and 18). In lines 20 and 21 we determine the sign for the x and y directions, specifying where the hero is with respect to this enemy. Remember, these can have values of 1, 0, or 1.

In lines 22 24 we insert the random dumbing-down process mentioned earlier in this section. This will cause the script to reverse the direction of an enemy approximately one out of every ten times it runs.

In line 26 we determine whether the enemy is in the same row or column as the hero. If he is not, then we randomly choose either the x direction or the y direction to move in. The direction we do not want to move in we set to 0. So, when xsign is set to 0, we will move toward the hero in the y direction. Next, in lines 34 39 we perform similar tasks for either the x or the y direction, depending on which is non-zero. For the direction that is non-zero we set the speed in that direction and also set the temporary variable dir to store the string value of the direction of motion. This is then used in line 52 to display a certain frame in the enemy movie clip so that the zombie appears to be walking in the correct direction. In lines 53 and 54 we store the newly established x and y velocities on the enemy object.


Are you interested in creating games along the lines of Pac-Man? The AI used here would probably work great for characters and figures like the ghosts in that game.

That's all of it! As far as AIs go, this one is elementary, but for simple games it is good enough.

Macromedia Flash MX Game Design Demystified(c) The Official Guide to Creating Games with Flash
Macromedia Flash MX Game Design Demystified: The Official Guide to Creating Games with Flash -- First 1st Printing -- CD Included
Year: 2005
Pages: 163
Authors: Jobe Makar

Similar book on Amazon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net