Game Actions


By now you can probably tell what's coming next. It's time to look at the game movie clip itself. In the game movie clip there are four layers. The Multiplayer Actions layer was discussed in the previous section. Here we will discuss the rest.

As you know, Don't Fall! is a game that's seen in the isometric view. The Iso Object layer contains the ActionScript needed to translate coordinates from 2D to 3D and back to 2D. It also gives us the depth to use for each tile so that we don't have to worry about z-sorting. All of this is done through the isometricAS object found in the Iso Object layer. In Chapter 8, "The Isometric Worldview," we talk about the isometricAS object and its methods in detail. The isometricAS object used here is exactly the same as the one found in Chapter 8, so we don't need to talk here about how it works. The Game Actions layer contains the ActionScript needed to build the game itself. We will talk about this frame in detail below. But first let's look at the Assets layer.

The Assets layer contains some user-interface elements. There is the Restart button, the little status window at the bottom right, and the pop-up movie clip that displays information like "You won!" and "Your opponent has left." Also in this frame is a movie clip off the left of the stage, with an instance name of soundfx. This movie clip contains two frames that have sounds on them: One of them has a sound of a tile falling, the other has the sound of a monster falling.

At this point you might be wondering where the monsters and tiles are hiding, since they are not on the stage. Good question! We are using attachMovie() to add the monsters and tiles; you'll find them in the library with linkage identifiers of character1, character2, and tile. There is one other movie clip we attach, with the linkage identifier of grid. This movie clip just serves as a container to hold all of the other movie clips we attach. That way, when it comes time to restart the game, we can just remove the container the grid movie clip and all of the tiles and monsters inside are automatically removed. The grid is then built again from scratch.

Now let's look at the ActionScript on the Game Actions layer of the game movie clip.

ActionScript Not Found in a Function

On the Game Actions frame there are several functions defined. But there are also some actions that are not defined as functions, because they need only be called once (in the process of setting up the game for each game session). You'll find them at the bottom of the frame. Here they are:

 1   maxx = 10; 2   maxz = 10; 3   iso = new isometricAS(maxx, maxz); 4   buildWorld(maxx, maxz); 5   popup.swapDepths(10); 6   soundOn = true; 

The first two lines define the size of the grid ten tiles in the x direction and ten in the z direction. (There is no need to define the size of the grid in the y direction because the grid is only two-dimensional [x and z] and it sits at the y position of 0.) Then we create a new instance of the isometricAS object and give it a reference name of iso. In line 4 we call the buildWorld() function, which creates the objects used to store information about the game. The buildWord() function calls the functions that add the tiles and the monsters. In line 5 we simply move the pop-up movie clip to a depth that is higher than everything else. That way it will not be covered by the movie clip that is attached in the buildWord() function (which is attached at a depth lower than 10).

onEnterFrame

This simple onEnterFrame event for this movie clip is the one that actually positions the characters in each turn; in that sense, it's sort of the "bread and butter" event of the game.

 1   this.onEnterFrame = function() { 2      moveCharacter(); 3      if (inPlay) { 4         positionCharacter(); 5      } 6   }; 

The moveCharacter() function is called in every frame. This function will only move a character if the character has not yet reached its destination. In that sense, it shuts itself off when it isn't needed. The positionCharacter() function is called only if the inPlay variable is true. The inPlay variable is set to true when the game is started, and set to false when the game is over. This function renders the position of the character onto the stage using the positions in memory set from the moveCharacter() function.

buildWorld()

The buildWorld() function is called when the frame first loads (as you saw above) and is also called from the restart() function. It handles creating the monsters, the tiles, and the container movie clip to hold them all. It also defines an onMouseMove and onMouseDown event onto the container clip, which is given an instance name of floor. Here is the function:

 1   function buildWorld(maxx, maxz) { 2      this.attachMovie("grid", "floor", 1); 3      world = new Object(); 4      world.depth = 10000; 5      world.maxx = maxx; 6      world.maxz = maxz; 7      world.cellWidth = 29; 8      world.width = maxx*world.cellWidth; 9      world.length = -maxz*world.cellWidth; 10     world.path = this.floor; 11     var path = world.path; 12     buildFloor(path); 13     if (ES.player == 1) { 14        name1 = ES.username; 15        name2 = ES.opponent; 16     } else { 17        name2 = ES.username; 18        name1 = ES.opponent; 19     } 20     buildCharacter(path, name1, 1, 1, 1); 21     buildCharacter(path, name2, 10, 10, 2); 22     floor.onMouseDown = function() { 23        if (!locked && myTurn && inPlay) { 24           this._parent.worldClicked(this._xmouse,               this._ymouse); 25        } 26     }; 27     floor.onMouseMove = function() { 28        updateAfterEvent(); 29        if (!locked && myTurn && inPlay) { 30           this._parent.over(this._xmouse, this._ymouse); 31        } 32     }; 33  } 

The function starts off by attaching the movie clip from the library that has a linkage identifier of grid and giving it an instance name of floor. It is attached at a depth of 1. All other movie clips that will be created are attached inside of floor.

Over the next several lines (3 10), the world object is created and is used to store information about the world. This is done just like it was in Chapter 8, "The Isometric Worldview." The path property stores a reference to the floor movie clip. In line 12 the buildFloor() function is called and the path reference is passed in. That function creates all of the tiles and uses path to know where to put them.

Lines 13 21 are used to create a monster for each player. First, two variables are created name1 and name2. The values of these two variables are the user names of the two players. We then call the buildCharacter() function, once for each of the two names. We pass the name to call the monster, the path reference, the x- and z-coordinates of the tile on which to place the monster, and the type of monster to use. There are only two monsters, so the type of monster can be either 1 (for the green monster) or 2 (for the blue monster).

The last thing the buildWorld() function does is define onMouseMove and onMouseDown event handlers for the floor movie clip. When the mouse is clicked, the onMouseDown event handler calls the worldClicked() function. The worldClicked() function determines if the character can walk where you just asked it to (by clicking). If the character can walk there without breaking the rules, then it is instructed to do so. When the mouse is moved, the onMouseMove event handler calls the over() function, which determines if your mouse is currently over a tile that your character can legally walk to. If it is, then a little circle animation is played over that tile.

buildCharacter()

This function is called from the buildWorld() function. It creates the object that stores information about the character that is being created, attaches a character movie clip from the library, and then calls the positionCharacter() function to place the movie clip over the correct tile. Here is the function:

 1   function buildCharacter(path, name, x_cell, z_cell, type) { 2      var clip = world.path.attachMovie("character"+type,         name, ++world.depth); 3      world[name] = new Object(); 4      world.char = world[name]; 5      world.char.tempx = world.cellWidth*x_cell-         world.cellWidth/2; 6      world.char.tempy = 0; 7      world.char.tempz = -(world.cellWidth*z_cell-         world.cellWidth/2); 8      world.char.speed = 4; 9      world.char.xmov = 0; 10     world.char.zmov = 0; 11     world.char.moving = false; 12     world.char.clip = clip; 13     world.char.x_cell = x_cell; 14     world.char.z_cell = z_cell; 15     currentOver = world.tiles[world.char.x_cell]         [world.char.z_cell]; 16     positionCharacter(); 17  } 

The first thing that happens in this function is that a character movie clip is attached from the library. As mentioned earlier, there are two characters in the library, character1 and character2. The character that is attached is decided by the type parameter passed in, which can be either 1 or 2. The name of the character movie clip being created is set from the name parameter passed in. The name parameter is also used to create an object that is used to store information about the character on the world object (line 3). In lines 5-7 we set the character's starting x, y, and z positions. We then initialize the speed variable, which controls how far the character walks in each frame until it reaches the destination (line 8). In lines 9 and 10, the character's initial velocity in the x and z directions is set to 0. We set the moving property on the character's object to false. That means the character is not moving. In line 12 a reference to the character movie clip is set on the object as clip. We also store the x_cell and z_cell values that are passed into this function on the character's object. These two values represent the current cell that the character is over. In line 15 we set a reference called currentOver. Remember that there is an array called tiles on the world object. Each element in this array is an object that represents a tile. The currentOver reference points to the object representing the tile that the character is currently over.

startGame()

This function is called when it is determined that both players are in the room, or when the restart() function is called.

 1   function startGame() { 2      flagStopped("yes"); 3      inPlay = true; 4      if (ES.player == 1) { 5         myTurn = true; 6         world.char = world[ES.username]; 7         var msg = "The game has started. It is your turn!"; 8      } else { 9         myTurn = false; 10        world.char = world[ES.opponent]; 11        var msg = "The game has started. It is your            opponent's turn!"; 12     } 13     popup.gotoAndStop("Game Started"); 14     popup.msg.text = msg; 15     me = world[ES.username]; 16     you = world[ES.opponent]; 17  } 

First we flag the game instance as being able to send or receive a move (line 2). We then set the inPlay variable to true. This tells some other functions, such as positionCharacter(), that it is OK to execute. Then we set the turn so that Player 1 can move first.

graphics/hand_icon.gif

It is important to note what is happening in lines 6 and 10. We set the reference world.char to point to the character whose turn it is. When the current turn is over, we set the world.char reference to point to the other character object. We create this reference and flip-flop what it points to as a convenience. In many of the functions you will see that we use world.char to access and modify values. This way we can easily change the object to which the reference points and still use the same functions. Also as a convenience, we set other references to the character objects in lines 15 and 16. These are used by the fall() function discussed later.

worldClicked()

The worldClicked() function is called when a tile is clicked. In it we map the mouse position into the isometric world. From that position we determine which tile area was clicked. We then check to see if that tile exists (if the tile has fallen, then it no longer exists). We also check to see if the tile that was clicked is adjacent to the one on which your character currently stands. If the tile exists and is adjacent to the character's tile, then we accept the click and call the function clickAccepted().

Here is the function:

 1   function worldClicked(xm, ym) { 2      var temp = iso.mapToIsoWorld(xm, ym); 3      var xm = temp[0]; 4      var zm = temp[1]; 5      var x_cell = Math.ceil(xm/world.cellWidth); 6      var z_cell = Math.ceil(Math.abs(zm)/world.cellWidth); 7      var xm = x_cell*world.cellWidth-world.cellWidth/2; 8      var zm = -(z_cell*world.cellWidth-world.cellWidth/2); 9      var x_cell_diff = world.char.x_cell-x_cell; 10     var z_cell_diff = world.char.z_cell-z_cell; 11     if (!world.char.moving && world.tiles[x_cell][z_cell].         exists && (x_cell_diff != 0 || z_cell_diff != 0) &&         ((x_cell_diff == 0 || Math.abs(x_cell_diff) == 1) &&         (z_cell_diff == 0 || Math.abs(z_cell_diff) == 1))) { 12         clickAccepted(xm, zm, x_cell, z_cell); 13         sendMove({type:"move", xm:xm, zm:zm, x_cell:x_cell,             z_cell:z_cell}); 14    } 15  } 

Take a look at lines 12 and 13. In line 12, clickAccepted() is called and the values for the mouse position and tile that was clicked are passed in. In line 13 we send the move to the other player. When the other player's game instance receives the move, then the moveReceived() function is called on in that player's instance. That game instance then calls the clickAccepted() function and passes in the information needed to move the character.

The clickAccepted() function rotates the character to walk in the direction that you clicked, and then starts the character moving in that direction.

determineFall()

When a character is set to move, the moveCharacter() function determines the next step for the character to take, and moves it there in memory. If it determines that the character has reached its destination, it calls determineFall(). This function tells the tile (the one that the character just left) to fall. It then checks the surrounding tiles to see if any of them have been destabilized enough to fall. (Remember that a tile needs to have at least one full side touching another to stay in the air.)

Here is the function:

 1   function determineFall() { 2      var x = world.char.old_x_cell; 3      var z = world.char.old_z_cell; 4      var ob = world.tiles[x][z]; 5      fall(ob); 6      checkTile(x-1, z); 7      checkTile(x, z+1); 8      checkTile(x+1, z); 9      checkTile(x, z-1); 10  } 

In lines 2 and 3 we set variables that store the position of the last tile that the character was over. In line 4 we create a reference to the object that represents that tile. Then a function called fall() is executed, and the tile object reference is passed in. That function handles making the tile fall. We will talk about that next. We then call the checkTile() function for each of the four neighbors of the tile that just fell. The checkTile() function checks to see if it is time for that tile to fall.

fall()

This function is called when it has been determined that a tile must fall. A reference to the object that represents the tile is passed in. We check to see if either of the monsters is on the tile. If one or both of the characters is on the tile, then we instruct the character to fall, and the game is over. Here is the function:

 1   function fall(ob) { 2      if (ob.x == me.x_cell && ob.z == me.z_cell) { 3         var clip = me.clip; 4         clip.ymov = 0; 5         clip.gravity = 1; 6         clip.char = true; 7         clip.onEnterFrame = fallFunction; 8         playSound("scream"); 9         iFell = true; 10        end = true; 11     } 12     if (ob.x == you.x_cell && ob.z == you.z_cell) { 13        var clip = you.clip; 14        clip.ymov = 0; 15        clip.gravity = 1; 16        clip.char = true; 17        clip.onEnterFrame = fallFunction; 18        playSound("scream"); 19        youFell = true; 20        end = true; 21     } 22     playSound("drop"); 23     ob.exists = false; 24     ob.clip.ymov = 0; 25     ob.clip.gravity = 1; 26     ob.clip.onEnterFrame = fallFunction; 27  } 

In lines 2-11 we check to see if the character whose game instance is running this code is on that tile. If so, then we play a scream sound and give the character an onEnterFrame event that makes it fall. Also, we set the variable iFell to true and end to true. Lines 12-21 do the exact same thing as 2-11, but for the other character. If that other character falls, then youFell is set to true and end is set to true. In either case, the drop sound is played (line 22) because the tile is falling. We set the exists property on the object that represents this tile to false. We do this so that if this space is clicked again, a character can't walk there. We then give the tile movie clip some initial variables and an onEnterFrame function so that it animates itself downward to imitate falling.

The moveCharacter() function uses the variables end, iFell, and youFell to determine if the game is over and who won. Here are the possible combinations.

Table 19.1. Who wins?
  Game Instance Settings  
Event Player 1 Player 2 Winner
Player 1 falls iFell=true youFell=true Player 2
Player 2 falls youFell=true iFell=true Player 1
Both fall iFell=true, youFell=true iFell=true, youFell=true Neither

checkTile()

This function is called from the determineFall() function, as seen above. It checks to see if the tile specified should fall.

 1   function checkTile(x, z) { 2      var ob = world.tiles[x][z]; 3      if (ob.exists) { 4         var ob1 = world.tiles[x-1][z]; 5         var ob2 = world.tiles[x][z+1]; 6         var ob3 = world.tiles[x+1][z]; 7         var ob4 = world.tiles[x][z-1]; 8         if (!ob1.exists && !ob2.exists && !ob3.exists &&            !ob4.exists) { 9             fall(ob); 10        } 11     } 12  } 

First we set a reference to the tile specified, called ob. If ob.exists is true, then we know that it is possible for the tile to fall. If ob.exists is not true, then the tile has already fallen or never existed in the first place. In lines 4 7 we set references to the four tiles that touch any of this tile's sides. If none of them exist, then this tile must fall. If any of them exist, then the tile can stay.



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
ISBN: B003HP4RW2
EAN: N/A
Year: 2005
Pages: 163
Authors: Jobe Makar

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