Link to Youtub animation videos
Side-scrolling games, also called platform games, first appeared in the early 1980s, and soon became the standard way to produce video games until 3D took over in the 1990s.
Side-scrolling platform games allow the player to control a character who is shown in side view. He can move left and right, and usually can jump. As he moves off the screen to one side, the background scrolls to reveal more of the play area.
NOTE
Platform games almost always feature a jumping character. The most famous is, of course, Nintendo’s Mario. He appeared in dozens of games, from Donkey Kong to numerous adventures on Nintendo’s consoles.
In this chapter, we build a fairly simple side-scrolling platform game with a main character that can move left and right and can jump. There will be walls and platforms. There will also be enemies, and items to collect.
Before we begin programming, let’s think through all the aspects of the game. We need a hero, enemies, items, and a way to build levels.
A very important aspect of platform games is level design. A platform game needs content, too. The content in this case is level design.
Someone—the programmer, an artist, or a level designer—needs to build levels. Figure
11.1 shows such a level, in fact the first level for our game.
Figure 11.1
Level 1 of our platform game features three enemies, several treasures, a key and a door.
More sophisticated platform games might also have a level editor. This would allow a level designer to create many different levels and try them out, while programmers and artists work on the rest of the game.
For our simple example, however, we’ll design the levels right in Flash, by building a movie clip containing the various game pieces.
The movie PlatformGame.fla contains various game pieces in its library. Here is a list:
●
Floor—A simple 40x40 block that the hero can stand on. It will block the hero
on the left and right side.
●
Wall—Identical to the floor in use, but visually different.
●
Hero—The player’s character. Includes stand, walk, jump, and die animations.
●
Enemy—A simpler character with a walk animation.
●
Treasure—A simple jewel, with animated sparkles.
●
Key—A simple key graphic.
●
Door—A door, with an open animation.
To create a level from these objects, they simply need to be dragged around and placed within a movie clip.
Figure 11.1 showed such a movie clip. It is actually the movie clip gamelevel1 in the library of the movie PlatformGame.fla.
To make it easy to build this level, I set a grid up using View, Grid, Edit Grid set to 40 by 40. Then, I dragged floor and wall pieces from the library and placed them along this grid.
Figure 11.2 shows the level with the background hidden so that you can see the grid marks.
Figure 11.2
Placing the wall and floor pieces along the grid makes it much easier to set up a level.
The wall and floor pieces in this game differ visually, but will both be seen as the same type of object in the code. You can add more “building block” pieces like this to make the game more diverse.
NOTE
An idea not used in this game is to have many different versions of the wall and floor blocks, all stored in different frames of the movie clip. Then, at the start of the game, a random frame is chosen for each block.
The walls and floor don’t need to be named anything special. However, the library elements are set to Export for ActionScript, as you can see in Figure 11.3. This is vitally important because our code will be looking for Floor and Wall objects.
Figure 11.3
The Floor movie clip is set to also be the class object Floor.
The hero is seen in Figures 11.1 and 11.2 at the upper left. He has been placed carefully so that he is standing right on a Floor block.
The hero’s movie clip has several different animated sections. Take a look at Figure
11.4.
Figure 11.4
The hero has frames for stand, walk, jump, and die.
Notice that the registration point for the movie clip rests at the very bottom of the character’s feet. We’ll be matching this up with the top of the Floor piece that the character is resting on. Horizontally, the character is centered.
When placing the hero, you’ll want the y position to match the y position of the Floor right underneath him. This way, the hero will start off standing. If you place him above a Floor block, he’ll start by falling onto the Floor. This is another way to go, as you may envision the character falling into the scene.
The enemy is a similar movie clip, but with just a stand and walk sequence. Figure 11.5 shows him. Note that the registration point for the enemy is also at the bottom of his foot.
Figure 11.5
The enemy character has just stand and walk labels.
These little guys are designed to be jumped on. In fact, that’s how the hero will get rid of them. So, they are short and squat. We don’t need a “die” sequence because we’ll be removing them from the screen the instant that they are destroyed, and using the PointBurst from Chapter 8, “Casual Games: Match Three,” to show a message in their place.
The enemies should also be placed directly matching a Floor piece. If not, they will drop down to the next Floor, which works out fine if that is how you want them to start.
The enemies also need to have instance names. The three shown in the Figures 11.1 and 11.2 are named enemy1, enemy2, and enemy3.
Another thing about enemies: They will be programmed to walk back and forth, turning around when they hit walls. So, you should place them in an area with walls on both sides. If they have a drop off to one side, they will fall down that drop off at the first opportunity. They will keep dropping down every time they get the opportunity, until they stabilize going back and forth in an area with walls on either end.
In Figures 11.1 and 11.2, you can see various other objects. The ruby-looking items are treasures that can be obtained for points. There is nothing remarkable about the Treasure movie clip, other than the fact that it has many frames to accommodate a looping sparkle animation. This does not affect the game in any way; it is just for visual interest.
If you want more than one type of treasure, the easy way to accomplish it is to place several treasures, one per frame, in that one movie clip. Otherwise, you must create a variety of different objects, such as Diamond, Coin, TheOneTrueRing, and so on. Then, you need to look for each one in the code.
The Key and Door movie clips are similar. The Key has some frames for animation only. The Door, on the other hand, has an “open” sequence starting on frame 2. Figure 11.6 shows this movie clip.
Figure 11.6
The Door movie clip has a static frame 1, and then a short animated sequence of it opening.
The items don’t need to be placed perfectly on the grid. They just need to be put in reach of the hero as he walks by, or in other cases, jumps. It does help visually if the door is resting on the ground, however.
NOTE
Pay attention to the layering of your game elements. This will be maintained while the game is being played. So, for instance, if the hero is behind a wall or other object, the wall appears in front of the hero graphic when the hero is close to it.
On the other hand, you can have objects appear in front of the player, like a semitransparent pane of glass or a small piece of furniture.
The Treasure, Key, and Door movie clips are all set to Export for ActionScript with class names to match their library names. Our code will be looking for them by class. The movie clip instances themselves don’t need to have any names.
One other item in the game is the Chest. This is a two-frame movie clip of a treasure chest closed, then open. It is the object of the player’s quest, and the game will end when the player finds it.
The game levels also include a layer in the movie clip with background art. In this case, it is a shaded gradient rectangle. However, there could be more. In fact, anything you add to the background will be visible, yet not active.
So, you can color in the scene however you want. There can be pictures hanging on the walls, animated torches, messages, and signs.
Figures 11.1 and 11.2 show torches hanging up high at the top. These are just placed on the same background layer as the gradient. Our game code won’t even need to acknowledge these because they will just scroll along with the background.
This movie will include a dialog box that we can bring up at any time to convey some information to players and await their input. You can see the dialog box movie clip in Figure 11.7.
Figure 11.7
The Dialog movie clip will be used to wait for the player to click a button before continuing.
The dialog box will be displayed when the player dies, the game is over, a level is complete, or the player wins. When any of these events happen, the game halts and a dialog box displays. We’ll include the dialog box as a separate movie clip, complete with a dynamic text field and a button.
The main timeline features a “start” frame with instructions. After that, each frame contains one game level movie clip. This makes it easy to jump from level to level, both while the game is playing and while you are creating the levels.
The second frame contains GameLevel1, which has an instance name of simply gamelevel. The third frame contains GameLevel2, which also has an instance name of gamelevel.
When the ActionScript executes, it looks for the movie clip with the instance name gamelevel on the current frame. This enables us to place different game level movie clips on different frames.
On the game level frames, we’ll have three dynamic text fields: one for the level, one for the number of lives remaining, and one for the score. Figure 11.8 shows what the screen looks like after the game begins.
Figure 11.8
There are three text fields at the bottom of the screen.
The class starts by examining the gamelevel movie clip. It loops through each of the children in this movie clip and figures out what it does and how it needs to be represented in the game class.
For instance, if a child is a Wall or Floor, it is added to an array of such objects. Then, when the characters move around, these objects are checked for collisions.
The hero and the enemies are also looked for. It is assumed that the hero has an instance name of hero, and the enemies are named enemy1, enemy2, and so on.
NOTE
To determine what type of object a movie clip is, we’ll be using the is operator. This operator compares the object type of a variable against an object type (for instance (ThisThing is MyObject)).
The largest part of the code, by far, is the part that deals with movement. The hero can move left, right, and he can jump. But, he is also affected by gravity and can fall off of edges. He can collide with walls and be stopped, and also collides with floors, which prevent him from falling through them.
The enemies do the same thing, except that their movements are not affected by the arrow keys. But, they still follow the same rules as the hero.
So, instead of having the hero and the enemies use different movement code, we’ll have them share a single character movement function.
Horizontal scrolling is another movement factor. The hero and enemies will move inside the gamelevel movie clip. If the hero’s relative position on the stage goes too far to the left or right, however, we’ll move the entire gamelevel movie clip to make it scroll. The rest of the code can ignore this because nothing will actually move inside the gamelevel.
Before we begin programming, let’s take a look at all of the functions that we will be using in the class, and which ones will rely on each other.
●
startPlatformGame—Initializes the score and player lives.
●
startGameLevel—Initializes the level, calling the next three functions.
●
createHero—Creates the hero object, looking at the placement of the hero movie clip instance.
●
addEnemies—Creates the enemy objects, looking at the enemyX movie clips.
●
examineLevel—Looks for walls, floors, and other items in the gamelevel movie clip.
●
keyDownFunction—Notes key presses by the user.
●
keyUpFunction—Notes when the user is done pressing a key.
●
gameLoop—Called every frame to calculate the time passed and then call the next four functions.
●
moveEnemies—Loops through all enemies and moves them.
●
moveCharacter—Moves the character.
●
scrollWithHero—Scrolls the gamelevel movie clip depending on the location of the hero.
●
checkCollisions—Check to see whether the hero hit any enemies or items. Calls the next three functions.
●
enemyDie—Enemy character is removed.
●
heroDie—Hero loses a life, game possibly over.
●
getObject—Hero gets an item.
●
addScore—Add points to the score, display the score.
●
showLives—Show the number of lives left.
●
levelComplete—Level is done, pause and display dialog.
●
gameComplete—Treasure is found, pause and display dialog.
●
clickDialogButton—Dialog button clicked, perform next action.
●
cleanUp—Remove the gamelist to prepare for the next level.
Now that we know the functions we need to write, let’s build the PlatformGame.as
class.
The package file is not particularly long, especially considering all that this game does. Because of that, we’ll keep everything in one class, even though it would be useful for a larger game to have separate classes for characters, items, and fixed objects.
At the start of the class, we can see our standard import listing, including the flash.utils.getTimer that we need for time-based animation:
package { import flash.display.*; import flash.events.*; import flash.text.*; import flash.utils.getTimer;
We need only a few constants. The first is gravity, and then also the distance to the edges of the screen is needed to start horizontal scrolling.
NOTE
The gravity constant was achieved through trial and error. Knowing that it would be multiplied by the number of milliseconds between steps, I started with a very low fraction. Then, I adjusted it after the game was complete, until I had the jump and fall behavior that seemed right.
public class PlatformGame extends MovieClip { // movement constants static const gravity:Number = .004;
// edge for scrolling
static const edgeDistance:Number = 100; When the gamelevel is scanned, all the objects found are placed in one of two arrays. The fixedObjects array holds references to any objects that the player can stand on or be blocked by. The otherObjects array holds items like the Key, Door, Chest, and Treasure:
// object arrays private var fixedObjects:Array; private var otherObjects:Array;
The hero movie clip is already named “hero” and can be accessed through gamelevel.hero. But the hero object in our class holds that reference, and many other pieces of information about the hero character. Similarly, the enemies array holds a list of objects with information about each enemy:
// hero and enemies private var hero:Object; private var enemies:Array;
A number of variables are needed to keep track of the game state. We’ll use playerObjects as an array to store objects that the player has picked up. The only one in the game is the Key, but we’ll store it in an array anyway to pave the way for more objects to be added.
The gameMode is a string that will help convey to various functions what has happened to the hero. It will start with a value of “start” and then get changed to “play” when the game is ready to go.
The gameScore and playerLives correspond to the number of points scored and the number of lives remaining for the player.
The lastTime variable holds the millisecond value of the last step of game animation. We’ll be using it to drive the time-based animation used by game elements:
// game state private var playerObjects:Array; private var gameMode:String = “start”; private var gameScore:int; private var playerLives:int; private var lastTime:Number = 0;
When the game starts, we need to set some of the game state variables. This is done by calling the startPlatformGame function on the frame that contains the first game level. We’ll have some other variables that need to be reset every level. Those are set when the startGameLevel is called on the next frame:
// start game
public function startPlatformGame() {
playerObjects = new Array();
gameScore = 0;
gameMode = “play”;
playerLives = 3;
}
Figure 11.9 shows the game start screen, with a button that the player must press to continue.
Figure 11.9
The start screen for the platform game.
The startGameLevel function is called on every frame that contains a gamelevel movie clip. It then delegates the tasks of finding and setting the hero, enemies, and game items:
// start level public function startGameLevel() {
// create characters createHero(); addEnemies();
// examine level and note all objects examineLevel();
The startGameLevel function also sets up three event listeners. The first is the main gameLoop function, which will execute each frame to push forward the animation. The other two are the keyboard event listeners we need to get player input:
// add listeners this.addEventListener(Event.ENTER_FRAME,gameLoop); stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction); stage.addEventListener(KeyboardEvent.KEY_UP,keyUpFunction);
Finally, the gameMode is set to “play”, and two functions are called to set up the display of the score and lives. The score display is updated with a call to addScore, which both adds a number of points to the score and updates the text field. So, if we add 0 points, it acts just like a display function:
// set game state gameMode = “play”; addScore(0); showLives();
}
The hero movie clip is already in the gamelevel movie clip and ready to go. But, we need to set and use many properties, so we’ll create a hero object in the class to store these properties:
// creates the hero object and sets all properties public function createHero() { hero = new Object();
The first property is a reference to the movie clip that is the visual representation of the hero. Now we can refer to the hero as hero.mc rather than gamelevel.hero. This will fit better when we are using the hero object for all our manipulations of the player’s character:
hero.mc = gamelevel.hero;
Next are two properties that describe the velocity of the hero: hero.dx = 0.0; hero.dy = 0.0;
The hero.inAir property will be set to true when the hero is not resting on solid ground:
hero.inAir = false;
The hero.direction property will be either –1 or 1, depending on the direction the hero is facing:
hero.direction = 1;
The hero.animstate property will hold either “stand” or “walk”. If it is “walk”, we’ll know that the character should be moving long its walk sequence. The frames in this sequence are stored in hero.walkAnimation. In this case, the walk sequence is on frames 2 through 8. To keep track of which step in the animation is currently showing, we’ll use hero.animstep:
hero.animstate = “stand”; hero.walkAnimation = new Array(2,3,4,5,6,7,8); hero.animstep = 0;
The hero.jump property is set to true when the player presses the spacebar. Similarly, the hero.moveLeft and hero.moveRight will toggle between true and false depending on whether the arrow keys are pressed:
hero.jump = false; hero.moveLeft = false; hero.moveRight = false;
The next few properties are constants used to determine how high the character jumps and how fast the character walks:
hero.jumpSpeed = .8; hero.walkSpeed = .15;
NOTE
These constants were also determined with trial and error. I started with educated guesses, such as the character should be able to walk about 100 to 200 pixels per second. Then I adjusted as I built the game.
The hero.width and hero.height constants are used when determining collisions. Instead of using the actual width and height of the character, which varies depending on which frame of animation is shown, we will use the following constants:
hero.width = 20.0; hero.height = 40.0;
When the hero does have a collision, we’ll be resetting him to his starting position in the level. So, we need to record this location for use at that point:
hero.startx = hero.mc.x; hero.starty = hero.mc.y; }
The enemies are stored in objects that look just like the hero object. With the hero and enemy objects having the same properties, we can feed either one into the moveCharacter function.
The addEnemies function looks for a movie clip named enemy1 and adds it to the enemies array, as an object. It then looks for enemy2 and so on.
One of the few differences between enemies and heroes is that enemies don’t need the startx and starty properties. Also, the enemy.moveRight property starts off as true, so the enemy starts by walking to the right:
// finds all enemies in the level and creates an object for each
public function addEnemies() { enemies = new Array(); var i:int = 1; while (true) {
if (gamelevel[“enemy”+i] == null) break; var enemy = new Object(); enemy.mc = gamelevel[“enemy”+i]; enemy.dx = 0.0; enemy.dy = 0.0; enemy.inAir = false; enemy.direction = 1; enemy.animstate = “stand” enemy.walkAnimation = new Array(2,3,4,5); enemy.animstep = 0; enemy.jump = false; enemy.moveRight = true; enemy.moveLeft = false; enemy.jumpSpeed = 1.0; enemy.walkSpeed = .08; enemy.width = 30.0; enemy.height = 30.0; enemies.push(enemy); i++;
} }
After the hero and all the enemies have been found, the examineLevel function looks at
all the children of the gamelevel movie clip: // look at all level children and note walls, floors and items public function examineLevel() {
fixedObjects = new Array();
otherObjects = new Array(); for(var i:int=0;i<this.gamelevel.numChildren;i++) { var mc = this.gamelevel.getChildAt(i);
If the object is a Floor or Wall, it is added to the fixedObjects array as an object with a reference to the movie clip, but also some other information. The locations of all four sides are stored in leftside, rightside, topside, and bottomside. We need quick access to these when determining collisions:
// add floors and walls to fixedObjects
if ((mc is Floor) || (mc is Wall)) { var floorObject:Object = new Object(); floorObject.mc = mc; floorObject.leftside = mc.x; floorObject.rightside = mc.x+mc.width; floorObject.topside = mc.y; floorObject.bottomside = mc.y+mc.height; fixedObjects.push(floorObject);
All other objects are added very simply to the otherObjects array: // add treasure, key and door to otherOjects } else if ((mc is Treasure) || (mc is Key) || (mc is Door) || (mc is Chest)) { otherObjects.push(mc); } } }
Accepting keyboard input will work using the arrow keys. However, we’ll directly set the moveLeft, moveRight, and jump properties of the hero. We’ll only allow jump to go to true if the hero isn’t already in the air:
// note key presses, set hero properties
public function keyDownFunction(event:KeyboardEvent) {
if (gameMode != “play”) return; // don’t move until in play mode
if (event.keyCode == 37) { hero.moveLeft = true; } else if (event.keyCode == 39) { hero.moveRight = true; } else if (event.keyCode == 32) { if (!hero.inAir) { hero.jump = true;
}
}
}