Flash Tutorial Links:
Play Games: HTML5 Tutorials:

How To Make A Platform Game (Part 2)

Now this is starting to look more like Super Mario.

Platform Games

Previously, we looked at a jumping game that works pretty much like the Mario platform games we're very used to. In a full-fledged platform game, a lot of actually goes into the level design. Which monster should we place here to challenge the players. How do we want the players to jump his way to secret levels or obtain hidden items.

If the level design behind the game is lacking, players will inevitably feel bored playing the game.

Here, I'll show you how to create a simple level design, using coins, bricks (platforms) and a vertically moving lift as the three key components of the game. I admit this is definitely not enough, but the techniques you learn here should be able to propel you forward. With the idea of the vertical lift, you can proceed on to do a horizontally moving lift as well.

Some of the key concepts you'll find in this tutorial is how to make the game screen scroll as your character moves, as well as how to implement your design ideas during design time, and not at runtime. So far, we've almost always generated game assets on the fly by some random chance. If you open up the FLA file, you'll see all the bricks or platforms already laid out for you. This design is done at design time.

You need to look at Tutorial 7 before proceeding on, because I will not discuss those concepts that were highlighted earlier on.

Game Scenario

Tooney the little green monster has previously climbed up the Waterfall, and is now ready to collect his shiny coins. These coins are precariously placed on platforms, some moving, and Tooney has to jump his way around to collect them all.

Help Tooney collect as many coins as you can!

Game Details

  1. The player controls the movement of Tooney with the LEFT, RIGHT keys.
  2. Tooney can be made to jump with the SPACEBAR key.
  3. Each coin Tooney collects earns him 10 points.
  4. Do not let Tooney fall off the platforms.

Download the Game Files

The files you need to create this game can be downloaded from here.

Step 1 - Managing your FLA file

In the library, you will see that there are quite a lot of movieclips. What's new are the Coin, VerticalLift and Markers movieclips. The Marker movieclip is a special movieclip, because it's not really a game asset which the player can see. Rather, it's a movieclip used at design time to mark out the start and end point of the scrolling behaviour. More on it later.

library

The Player movieclip is similar to what you saw in Tutorial 7. It has the same hitAreaFloor movieclip in it to mark out the area which will detect if Tooney landed on a brick.

player

For the detailed explanation on this, please check out Tutorial 7 first.

Step 2 - Starting up the game in your GameController.as

Let us see what goes on in the startGame function.

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public function startGame()
{
    playerScore = C.PLAYER_START_SCORE;
            
    gameObjects = new Array();
    bricks = new Array();
    coins = new Array();
    lifts = new Array();
    
    scrollSoFar = 0;
    moveX = 0;
    jump = false;
    
    setUpGame();
    
    //Add player on to stage
    player = new Player(C.PLAYER_START_X, C.PLAYER_START_Y);
    mcGameStage.addChild(player);
    
    //Hide Markers
    mcGameStage.mcStartMarker.visible = false;
    mcGameStage.mcEndMarker.visible = false; 
    
    mcGameStage.addEventListener(Event.ENTER_FRAME,update);
    
    //Handle event when this game is being preloaded
    addEventListener(Event.ADDED_TO_STAGE, gameAddedToStage ); 
    
    //Handle situations when this game is being run directly
    if (stage != null)
    {
        stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownHandler);
        stage.addEventListener(KeyboardEvent.KEY_UP,keyUpHandler);
    }
}

You may observe that we have a lot of arrays here, each one storing a type of game object. What's most interesting here is perhaps gameObjects. It is an array which we'll use to scroll all the objects that should scroll later on. It's going to store a mixture of the bricks, lifts, etc.

We'll look at line 61 in detail shortly. setUpGame is the function which will look at all the game objects you've placed inside the mcGameStage and then sort them out into their proper arrays. More on that later.

Lines 68 and 69 turns the visibility property of the markers off, so that the player will not see it at all. These markers are still useful later when we do the scrolling logic, but the player does no need to see them.

Step 3 - Key Handlers

The key handlers are exactly the same as that in Tutorial 7. The keyboard input to the game will be the LEFT, RIGHT and SPACEBAR keys. Feel free to add in the support for the A and D keys as well if you want.

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
private function keyDownHandler(evt:KeyboardEvent):void
{
    if (evt.keyCode == 37) //LEFT Key 
    {
        moveX = -1;
    }
    else if (evt.keyCode == 39) //RIGHT Key
    {
        moveX = 1;
    }
    
    if (evt.keyCode == 32) //Spacebar
    {
        jump = true;
    }
}

jump is just a boolean variable. We set it to be true when the player hits the spacebar.

Step 4 - setUpGame

The game objects that we placed inside mcGameStage needs to be properly analysed and understood by the Game Controller. Otherwise, the player will not be able to interact with them. Hence, once the game is called to start, we call the function setUpGame to sort things out.

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
private function setUpGame()
{
    //Loop through all items on stage
    for (var i=0; i< mcGameStage.numChildren; i++)
    {
        var currObject = mcGameStage.getChildAt(i);
        
        //Identify the bricks
        if (currObject is Brick)
        {
            bricks.push(currObject);
            gameObjects.push(currObject);
        }
        else if (currObject is Coin)
        {
            coins.push(currObject);
            gameObjects.push(currObject);
        }
        else if (currObject is VerticalLift)
        {
            lifts.push(currObject);
            gameObjects.push(currObject);
        }
    }
}

numChildren in line 123 stores the total number of child objects inside mcGameStage. When we drag all those movieclips into mcGameStage, they are all considered the children of mcGameStage. So what this for loop does is to loop through all the children.

In line 128, we see this new syntax, currObject is Brick. Although we can tell that it REALLY IS a Brick object, but it is known to Flash only as a DisplayObject, basically. What this "is" syntax does is to check if the currObject is of class Brick. It returns true if it is, false if otherwise.

If it is a Brick, we push it into the array bricks, as well as the array gameObjects.

We do the same for coins, and vertical lifts. After we are done with this function setUpGame, our arrays are already properly storing the respective game objects. The array gameObjects will store all the game objects that should scroll when the player moves.

Step 5 - Game Loop - User Input

The codes to handle the user input are exactly the same as that in Tutorial 7. There isn't any new code to make the movement here work. Please head over to Tutorial 7 if you need help.

Step 6 - Game Loop - Game Logic

We will only highlight the code that is unique in this tutorial from the previous. You can see that there is a new game mechanic here, that is the vertical lifts. At the start of the game logic, we update the lifts.

164
165
166
167
168
169
170
171
//******************
//Handle Game Logic
//******************
//Update lifts
for (var i=lifts.length - 1; i >= 0; i--)
{
    lifts[i].update();
}

Let's take a look at what goes on in the VerticalLift class.

20
21
22
23
24
25
26
27
28
public function update()
{
    this.y += this.dirY * C.VERTICAL_LIFT_SPEED;
    if ((this.y <= this.startPosY - C.VERTICAL_LIFT_MAX_DISTANCE) ||
        (this.y >= this.startPosY + C.VERTICAL_LIFT_MAX_DISTANCE))
    {
        this.dirY *= -1;
    }
}

The variable dirY indicates which direction the lift is going to move towards. We mulitply it by the speed of the lift, denoted by C.VERTICAL_LIFT_SPEED, and modify the y position accordingly. Lines 23 to 27 checks if the lift has reached it's maximum distance that it should travel, and if so, flip the direction around by multiplying dirY by -1.

You do not have to worry how to make the player move if the player is standing on the lift. Remember that there is a property in the Player class which is standingOn, and that denotes the platform the player is on. During the player's update, his location will be updated to the platform's coordinates accordingly.

Now let us go back to the game logic in the game loop.

173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
//Update Player
player.update();
    
//Check for collisions
if (player.isInAir() && player.isFalling())
{	
    for (var i=bricks.length - 1; i >= 0; i--)
    {
        if (player.hitAreaFloor.hitTestObject(bricks[i]))
            {
                //Player landed on the brick
                player.hitFloor(bricks[i]);
            }
    }
	
    for (var i=lifts.length - 1; i >= 0; i--)
    {
        if (player.hitAreaFloor.hitTestObject(lifts[i]))
        {
            //Player landed on the lift
            player.hitFloor(lifts[i]);
        }
    }
}

The code here is exactly the same as previous, but we added the check for collisions between the player and the lifts now from line 188 to line 195.

The code isn't very different though. But because the player can now land on either the Brick, or the Lift, we amended the hitFloor function in the Player class slightly. Instead of locking in whether it is a Brick or a Lift, we use the * to denote any possible class.

145
146
147
148
149
150
public function hitFloor(platform:*)
{
    this.inAir = false;
    this.standingOn = platform;
    this.y = platform.y;
}

The next part in the update function of the GameController checks for collision of the player and the coins, which is trivial. We do the usual updating of the player's score and remove the coins.

Step 7 - Player's update Function

There are some major changes in the update function of the player which are worth highlighting. Remember that this game is now scrollable, meaning that when the player moves, the window will scroll accordingly. We will only look at scrolling in the x direction, and not in the y direction.

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public function update()
{
    //Move Horizontally
    if (this.speedX < 0)
    {
        //Check if player should move
        if (MovieClip(root).playerShouldMoveLeft())
        {
            this.x += this.speedX;
        }
        else
        {
            MovieClip(root).scrollGameObjects(-this.speedX);
        }
    }
    else if (this.speedX > 0)
    {
        //Check if player should move
        if (MovieClip(root).playerShouldMoveRight())
        {
            this.x += this.speedX;
        }
        else
        {
            MovieClip(root).scrollGameObjects(-this.speedX);
        }
    }

You can see that in the new code, the movement in the x direction is no longer a straightforward modification based on speedX. This is actually related to relative velocity (argh... more Physics?!?)

To make the player perceive that the game character Tooney is moving to the right when the player hits the RIGHT key, we can simply just move Tooney's x position by a positive value. But, consider the fact that we can also move everything else in the x direction by a negative value. The illusion still remains that we see the player move to the right.

In line 35, we make a check back to the GameController to see if the player should be moving, or if the game objects should be moving. This is where the markers come in handy. Let's jump back to the GameController now.

233
234
235
236
237
public function playerShouldMoveLeft():Boolean
{
    return ((mcGameStage.mcStartMarker.x >= 0) ||
            (mcGameStage.mcEndMarker.x - player.x <= C.SCROLL_BOUND));
}

Examine the code above that determines if it is the player who should be moving, as opposed to the fact that the game objects should be scrolling.

scrollDiagram

This diagram above tries to illustrate who should scroll. Basically if the player is moving towards the end of the screen where the mcStartMarker or the mcEndMarker is already at the edge, then the player should be moving physically. Otherwise, where he has moved away from the markers enough, all the game objects stored in the gameObjects array will scroll instead to create this illusion of motion.

The markers move as well when the other gameObjects scroll. Their whole purpose in this game is to denote the front and back of the entire game level.

This is probably the hardest part to understand in this tutorial. Do take some time and examine the codes in detail.

The Game

And here you have it ... the working game! There are actually a lot more interesting mechanics we can add to the platform game, such as adding horizontally moving platforms, platforms that disappear when you land on them, monsters for you to step on, etc.

Download the Game Files

The files you need to create this game can be downloaded from here.

How To Play

Objective: Collect all the coins without letting Tooney fall off the platforms.

Controls: Press LEFT and RIGHT keys to move Tooney. Press SPACEBAR to jump.


Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player


Flash Resources
Preloader FPS Display Sounds & Music
Keycodes Name Generator
Game Development Resources
Sprite Sheets