Flash Tutorial Links:
Play Games: HTML5 Tutorials:

Make Music Games

Blocks are falling, music is pounding, can your hands keep up?

Rise of Music Games

Musical games gained immense popularity of the late when Guitar Hero, Rock Band, etc took the gaming world by storm. These games test the players reflexes by listening to some pop music, and watching little bricks or game objects fall. When these objects fall, the player is supposed to hit the right buttons, and get points according to how perfect his timing is.

We've seen some similar game mechanics back then when Dance Dance Revolution was pretty popular in arcade centres (and made its way to the homes of some people). That involved hitting the correct directional buttons.

In this tutorial, we'll try to recrate a simplified game with this form of game mechanics. I'll leave out the music and addition of sound effects to another tutorial. We'll focus solely on the coding of the game for now.

Game Scenario

Do we really need a game scenario for this kind of game? Ok, how about ... musical bricks are dropping down, and the player needs to hit the right keys according to the kind of musical brick, at the right time.

Game Details

  1. The player hits the keys Q, W, O and P for the Blue, Red, Green, and Yellow bricks respectively.
  2. Each perfect timing gets the player 50 points, a good timing 10 points, and a bad timing a penalty of -20 points.

Download the Game Files

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

Step 1 - Managing your FLA file

In this tutorial, a lot of graphics have been laid out on the screen to supplement the game.

musicGamestage

The text fields, the outlines of the bricks, as well as the letters (which tell the player which key to press for which brick) are all parked under the UI layer. Remember that this layer is there for such purposes of holding UI elements like these, as they will always be above the game assets (since UI layer is one layer higher than Contents)

One Brick movie cilp is used to hold all the four colour types of bricks, and they are differentiated by the frame they are currently at.

brick Structure

When we create the bricks, we just need to gotoAndStop at the correct frame label to get the correct colour of the brick displayed to the player.

If you look at the centre of the game stage, you will see another text field labelled txtStatus. This text field is used to display to the player how accurate his gameplay is. It will show Perfect, Good or Bad, and the text will slowly fade after it pops up for a while.

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

Let us see what goes on in the startGame function.

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public function startGame()
{
    playerScore = C.PLAYER_START_SCORE;
			
    bricks = new Array();
    showText = "";
    showTextTimer = 0;
    
    txtStatus.blendMode = BlendMode.LAYER;
    
    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);
    }
}

The only interesting code here is probably line 55. For now, let's just say that the reason for this line of code is to enable the transparency fading of the txtStatus text field. I think this code would not be required anymore if it is targeted to Flash Player 10, but anything lesser, the dynamic text fields are not really able to change in their alpha property properly it seems.

Step 3 - Key Handlers

The keyboard input to the game will be the letters Q, W, O and P. We chose two sets of letters that are grouped far apart (group for Q and W, and a group for O and P) for obvious reasons of hand positioning. It is intended that the player plays with his two hands on the keyboard, left hand for Q and W, while the right hand for the other two.

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
private function keyDownHandler(evt:KeyboardEvent):void
{
    if (evt.keyCode == 81) //Letter 'Q' 
    {
        pressQ = true;
    }
    if (evt.keyCode == 87) //Letter 'W'
    {
        pressW = true;
    }
    if (evt.keyCode == 79) //Letter 'O'
    {
        pressO = true;
    }
    if (evt.keyCode == 80) //Letter 'P'
    {
        pressP = true;
    }
}

We set the keypresses accordingly in the variables pressQ, pressW, pressO and pressP.

Step 4 - Game Loop - User Input

Now, let us consider the user input portion in the game loop. You can see that it is clearly broken up into several if statements, each handling the situation of a specific keypress. They all call the same function, checkBrick, which takes in a string that is either "blue", "red", "green" or "orange", accordingly.

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
public function update(evt:Event)
{
    //******************			
    //Handle User Input
    //******************
    if (pressQ)
    {
        checkBrick(C.COLOUR_FOR_Q);
    }
    
    if (pressW)
    {
        checkBrick(C.COLOUR_FOR_W);
    }
    
    if (pressO)
    {
        checkBrick(C.COLOUR_FOR_O);
    }
    
    if (pressP)
    {
        checkBrick(C.COLOUR_FOR_P);
    }
    
    pressQ = false;
    pressW = false;
    pressO = false;
    pressP = false;

After doing the checks, we set all the variables to false so as not to have the game over-react to the player's input.

So what actually happens in the checkBrick function?

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
public function checkBrick(colour:String)
{
    var foundABrick = false;
        
    for (var i=0; i < bricks.length; i++)
    {
        if (bricks[i].getColour() == colour)
        {
            foundABrick = true;
            
            //Check how close this brick is to the PERFECT location
            var distToPerfect = C.PERFECT_YPOS - bricks[i].y;
            
            if ((distToPerfect < C.PERFECT_DISTANCE) && 
                (distToPerfect >= C.HIT_TOLERANCE))
            {
                //Brick is at a perfect distance
                playerScore += C.PERFECT_POINTS;
                showText = C.STATUS_PERFECT;
                showTextTimer = C.TXTSTATUS_MAX_TIMER;
                
                //Remove Brick
                mcGameStage.removeChild(bricks[i]);
                bricks.splice(i,1);
            }
            else if ((distToPerfect < C.GOOD_DISTANCE) && 
                    (distToPerfect >= C.HIT_TOLERANCE))
            {
                //Brick is at a good distance
                playerScore += C.GOOD_POINTS;
                showText = C.STATUS_GOOD;
                showTextTimer = C.TXTSTATUS_MAX_TIMER;
                
                //Remove Brick
                mcGameStage.removeChild(bricks[i]);
                bricks.splice(i,1);
            }
            else
            {
                //Very bad timing for hits
                playerScore += C.BAD_POINTS;
                showText = C.STATUS_BAD;
                showTextTimer = C.TXTSTATUS_MAX_TIMER;
            }
            
            //already found 1 brick, exit
            break;
        }
    }
    
    if (!foundABrick)
    {
        //Hit key when there isn't a brick
        playerScore += C.BAD_POINTS;
        showText = C.STATUS_BAD;
        showTextTimer = C.TXTSTATUS_MAX_TIMER;
    }
}

Line 184 and 186 loops through all the bricks that are stored in the bricks array, and filters out only those bricks that belong to the colour which we're going to check. If the function is called with checkBrick(C.COLOUR_FOR_Q), it effectively means we're doing checkBrick("blue"). So, even when we loop through all the bricks in line 184, line 186 ensures that we only look at the blue bricks.

Because we only look at 1 brick each time the user presses a key, the variable foundABrick controls that.

Also notice that although we've always been doing the loops from the back of the array to the front, here, we're actually looping from the front to the back. The reason is that we want to select the bricks lowest in the game with the highest priority. As the bricks are created, they are pushed into the bricks array. This means that bricks with the lower array indices, are the bricks that are lowest in the game.

bricks priority illustration

This illustration above should show you what I was trying to highlight earlier. If the player presses the W key, pressW will be true, and that in turn calls the function checkBrick("red"). Inside the checkBrick function, we have to loop from the front of the array so that we correctly selects bricks[0] instead of bricks[1].

190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
            //Check how close this brick is to the PERFECT location
            var distToPerfect = C.PERFECT_YPOS - bricks[i].y;
            
            if ((distToPerfect < C.PERFECT_DISTANCE) && 
                (distToPerfect >= C.HIT_TOLERANCE))
            {
                //Brick is at a perfect distance
                playerScore += C.PERFECT_POINTS;
                showText = C.STATUS_PERFECT;
                showTextTimer = C.TXTSTATUS_MAX_TIMER;
                
                //Remove Brick
                mcGameStage.removeChild(bricks[i]);
                bricks.splice(i,1);
            }
            else if ((distToPerfect < C.GOOD_DISTANCE) && 
                    (distToPerfect >= C.HIT_TOLERANCE))
            {
                //Brick is at a good distance
                playerScore += C.GOOD_POINTS;
                showText = C.STATUS_GOOD;
                showTextTimer = C.TXTSTATUS_MAX_TIMER;
                
                //Remove Brick
                mcGameStage.removeChild(bricks[i]);
                bricks.splice(i,1);
            }
            else
            {
                //Very bad timing for hits
                playerScore += C.BAD_POINTS;
                showText = C.STATUS_BAD;
                showTextTimer = C.TXTSTATUS_MAX_TIMER;
            }
            
            //already found 1 brick, exit
            break;

After we found that brick, we need to check its position from the perfect position. Since nowhere in the game will this perfect position be changed, we've put this perfect y coordinates into the C.as already, under C.PERFECT_YPOS.

In line 191, we take this perfect position - the current y coordinates of the brick. This gives the distance the brick is from the perfect position. While it makes sense to test the player harshly to get a distance of 0 here, meaning for the brick to be EXACTLY at the perfect location, this is actually poor game balancing, because he is going to end up without seeing any Perfect ever. Instead, we set a tolerance distance. As long as the distance falls within this range, we take it as Perfect.

distance diagram

Essentially, what lines 193 and 194 are checking for, is that the brick falls within the PERFECT_DISTANCE and HIT_TOLERANCE area.

If it does, we update the player's score, remove the brick, etc. Else, in lines 217 to 223, we consider this a bad timing, and impose the penalty to the player's score accordingly.

230
231
232
233
234
235
236
237
    if (!foundABrick)
    {
        //Hit key when there isn't a brick
        playerScore += C.BAD_POINTS;
        showText = C.STATUS_BAD;
        showTextTimer = C.TXTSTATUS_MAX_TIMER;
    }
}

These lines of codes handle the scenarios whereby the player wildly mashes his keys just to get the timing right by brute force. If foundABrick is not true, which means that as we loop through all the bricks, we did not find a colour matching the key he pressed, we impose the same bad timing penalties.

This is probably the heaviest user input logic we've seen so far. :)

Step 5 - Game Loop - Game Logic

131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//******************
//Handle Game Logic
//******************			
//Check to spawn bricks
if (Math.random() < C.SPAWN_BRICK_CHANCE)
{
    var newBrick = new Brick();
    bricks.push(newBrick);
    mcGameStage.addChild(newBrick);
}
 
//Update Bricks
for (var i=bricks.length - 1; i >= 0; i--)
{
    bricks[i].update();
    
    if (bricks[i].notInScreen())
    {
        mcGameStage.removeChild(bricks[i]);
        bricks.splice(i,1);
        
        //Consider a miss
        playerScore += C.BAD_POINTS;
        showText = C.STATUS_BAD;
        showTextTimer = C.TXTSTATUS_MAX_TIMER;
    }
 
}

The amount of game logic required to maintain the game is much shorter this time round. We have the usual code to check for spawning of the bricks from line 135 to 140. There are 4 different types of bricks that could spawn, and this is handled in the constructor of the Brick class.

10
11
12
13
14
15
16
17
18
public function Brick()
{
    var colourIndex = Math.floor(Math.random()*4);
    colour = C.COLOUR_ARRAY[colourIndex];
    this.x = C.COLOUR_START_X[colourIndex];
    this.y = C.COLOUR_START_Y;
    
    this.gotoAndStop(colour);
}

As the brick is created, a random colour is selected by the code shown above. We merely forward the frame of the brick to the appropriate colour. The rest of the code in the Brick class are rather straightforward.

Now, back to the game logic in the game loop.

131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//******************
//Handle Game Logic
//******************			
//Check to spawn bricks
if (Math.random() < C.SPAWN_BRICK_CHANCE)
{
    var newBrick = new Brick();
    bricks.push(newBrick);
    mcGameStage.addChild(newBrick);
}
 
//Update Bricks
for (var i=bricks.length - 1; i >= 0; i--)
{
    bricks[i].update();
    
    if (bricks[i].notInScreen())
    {
        mcGameStage.removeChild(bricks[i]);
        bricks.splice(i,1);
        
        //Consider a miss
        playerScore += C.BAD_POINTS;
        showText = C.STATUS_BAD;
        showTextTimer = C.TXTSTATUS_MAX_TIMER;
    }
 
}

From line 143 to 156, we loop through each of the brick in the bricks array, and update them accordingly. If you refer back to the Brick class, the update function simply moves the brick downwards.

In line 147, we check if the bricks have reached a certain distance below the perfect y, where the player should have hit the right button. If the player has yet to, the brick will survive past the perfect y, and trigger these code where we consider the player having missed his chance. The usual penalty applies in line 153, where we deduct the player's score.

You'll see why we set this variable showTextTimer in line 155 later on. This variable is used to trigger the text updates where the player sees Perfect, Good, or Bad.

Step 6 - Handling Display

160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//******************
//Handle Display
//******************
//Display status alerts
showTextTimer -= C.TXTSTATUS_DECREASE_TIMER;
if (showTextTimer > 0)
{
    txtStatus.text = showText;
    txtStatus.alpha = showTextTimer/C.GAME_FPS;
}
else
{
    txtStatus.text = "";
    txtStatus.alpha = 0;
}			
 
//Display new Score
txtScorePlayer.text = String(playerScore);

We have a little extra thing to show besides the usual playerScore. The status alert is shown whenever the showTextTimer is greater than 0. That's why we see earlier on that whenever the player gets a Perfect hit, a Good hit, or a miss, we always set the showTextTimer to C.TXTSTATUS_MAX_TIMER.

We then slowly reduce the alpha of the text field by a little each tick of the loop, until the time when showTextTimer reaches 0, and we'll clear the status text totally by setting the alpha to be 0.

The Game

And here you have it ... the working game! If you like it ... share it!

Download the Game Files

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

How To Play

Objective: Hit the bricks with the correct key when it falls into the brick outline.

Controls: Press Q for the Blue brick, W for Red, O for Green and P for Yellow.


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


Posted by Joseph

on 2014-12-04 23:10:17

Download Flash CC? =)


Posted by whamer100

on 2014-09-15 08:44:57

where do i get the program to make these?!


Posted by devit

on 2014-04-22 14:38:33

Hi, Can you help me how to make this game over ??
I'm try for make game over but it's still failed...
Thank you


Posted by devit

on 2014-04-09 02:58:37

thanks for the tutorial that you give it very helpful ....
I would like to request permission to use this tutorial as my final project
because it already has a license tutorial so before I use it I want to ask for permission.
you can send the answer to my email.
Thank you very much...


Posted by reginah

on 2012-12-30 12:14:11

i agree


Posted by Joseph

on 2012-12-20 00:00:25

Game menus and back can be found in other tutorials of mine, for e.g. :
http://www.makeflashgames.com/tutorials/simon/index.php


Posted by Wind

on 2012-10-13 05:24:14

Hey nice tutorial, very rare to find a DDR style game tutorial.
Can you add a tutorial on how to link the game menu to this game, and add a button to go back to the menu?


Posted by darkxell

on 2012-07-30 10:28:32

and sir how to stop the game and display the highscore?


Posted by darkxell

on 2012-07-30 10:25:18

Thanks for this tutorial. but is it possible to play this game
in a dance pad?


Posted by radith

on 2012-03-30 17:32:18

super great tutorial
i wonder if i can arrange the bricks manually, i mean to match it with the beats from the song. Could you give me any solution ?


Posted by Ivan

on 2011-12-12 04:18:40

I don't understand how/where declare (in the GameController.as) and What is really the mcGameStage... Can you explain this a little bit? What is the role of mcGameStage? where ist declared?

Thank You :)


Posted by Joseph

on 2010-12-20 11:06:26

Hi Anon, thanks for the kind comments, and sorry for missing out this post. Afraid that I probably won't be enhancing this particular tutorial in the near future, but you can find help for your qns in the other tutorials.

I have a section on playing sounds (under misc tutorials) si that should take care of adding real music to the game.

For more complex handling of the game like menu screens, difficulty selections, you can reference my tower defence tutorial under advanced tutorials.

Hope these will provide some good help to you.


Posted by Anon

on 2010-12-08 14:09:36

Hi there, thanks for the awesome tutorial. It totally works for me,anyway is there any further advancements to this game?
Loading stages like easy, medium or hard with song selections?
and is there a way to stop the music and display high score?

this is urgent, hope you reply asap!!
thanks!! :)


Posted by Anon

on 2010-12-07 14:45:22

Is it possible to add songs to the rhythm?
and is there a way to stop the game? and put a high score?
:)


Posted by Joseph

on 2010-06-29 13:43:40

Hi, Thanks for dropping by. Doing vids may be a possibility in future, but I'm not sure if it is the best way to present such technical tutorials.

You can probably highlight the areas you're unsure of?


Posted by lol

on 2010-06-23 02:57:52

i dont uderstand too much this tutorial can u make vids plzz


Flash Tutorial Links:
Play Games: HTML5 Tutorials:
gaming tools download on app store now!
Home | About Us | Contact Us
Powered by Make Flash Games. All Rights Reserved.
By Joseph Tan