Jul 08 2008

Flash Game Creation - Raiden

Published by Andy G. Cook at 7:11 pm under Flash, Game Design, Intermediate

Do you remember the game Raiden? I remember pumping quarter after quarter into the Raiden machine at my local Papa Ginos. The shop no longer has that game within its doors, and was replaced by a trash barrel a few years back.

We can fix the problem though. We can just build the game ourselves!

For those of you unfamiliar with the game…here is a link to one of the many Flash tributes made to the original game. Check it out.

The very first thing you need is a ship. I don’t like having anything manually on my stage, so we are going to add the ship through code. In order to do this, you have to give the ship a class path.

You get this pop up by going into your library, right clicking whatever you want to be your ship, and then going to linkage.

Linkage Pop-Up

If you get a pop up saying the class doesn’t exist, just hit OK. Flash will automatically build one for you.

Now are ready to start coding.

Adding the ship:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package
{
	import flash.display.Sprite;
	import flash.display.MovieClip;
	import flash.display.Stage;
 
	public class Main extends Sprite
	{
		private var GameShip:Ship;
 
		public function Main ( ) : void
		{
			GameShip = new Ship ( );
			stage.addChild(GameShip);
			GameShip.x = stage.stageWidth/2;
			GameShip.y = stage.stageHeight - 50;
		}
	}
}

Line 1: Starting the package

Lines 3-5: Importing the necessary classes for this code.

Line 7: Initiating my class. The Class has to be the same name as the Document Class. I am extending sprite so I can actually put stuff onto the stage. Also, I am extending sprite instead of extending movieclip because I am not actually going to put any code on the timeline and I am not going to be using any frame past frame one. Therefore, I am extending the lighter sprite.

Line 9: Making a private class variable of type Ship. The type should match whatever you made the class in the class path above.

Lines 11-17: Making a constructor for my class and adding the ship to the stage in the constructor so it is added automatically. I just set the X and Y values of my ship to be half the stage width and a little above the stage height. I use the stage.stageWidth and stage.stageHeight instead of static values because sometimes I might want to change the size of my Flash movie, and if I do that, I would have to go back into all my code and fix the static values.

Moving the ship:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package
{
	import flash.display.Sprite;
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.events.KeyboardEvent;
 
	public class Main extends Sprite
	{
		private var GameShip:Ship;
 
		public function Main ( ) : void
		{
			GameShip = new Ship ( );
			this.addChild(GameShip);
			GameShip.x = stage.stageWidth/2;
			GameShip.y = stage.stageHeight - 50;
 
			stage.addEventListener ( KeyboardEvent.KEY_DOWN, keyDownHandler );
		}
 
		private function keyDownHandler ( KBE:KeyboardEvent ) : void
		{
			switch ( KBE.keyCode )
			{
				case 37:
				GameShip.x -= 5;
				break;
 
				case 38:
				GameShip.y -= 5;
				break;
 
				case 39:
				GameShip.x += 5;
				break;
 
				case 40:
				GameShip.y += 5;
				break;
			}
		}
	}
}

Line 6: Imported the KeyboardEvent class

Line 19: Added a KeyboardEvent listener to listener to the stage for when a key goes down.

Lines 22-43: Setup a switch statement to move the ship according to what key is down. 37 is left. 38 is up. 39 is right. 40 is down. Then I just added/subtracted 5 pixels to the position of the ship.

Moving the Ship Version 2.0:

The ship is moving really choppy. Also, there is a kind of hiccup after the first key press. And it is only going in the last direction that was pressed because of the key listener only registering the last key that was pushed down. We can fix this using the ENTER_FRAME event.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package
{
	import flash.display.Sprite;
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.events.KeyboardEvent;
	import flash.events.Event;
 
	public class Main extends Sprite
	{
		private var GameShip:Ship;
 
		private var bLeftKeyDown:Boolean;
		private var bUpKeyDown:Boolean;
		private var bRightKeyDown:Boolean;
		private var bDownKeyDown:Boolean;
 
		public function Main ( ) : void
		{
			GameShip = new Ship ( );
			this.addChild(GameShip);
			GameShip.x = stage.stageWidth/2;
			GameShip.y = stage.stageHeight - 50;
 
			stage.addEventListener ( KeyboardEvent.KEY_DOWN, keyDownHandler );
			stage.addEventListener ( KeyboardEvent.KEY_UP, keyUpHandler );
			stage.addEventListener ( Event.ENTER_FRAME, onEnterFrameHandler );
		}
 
		private function keyDownHandler ( KBE:KeyboardEvent ) : void
		{
			switch ( KBE.keyCode )
			{
				case 37:
				bLeftKeyDown = true;
				break;
 
				case 38:
				bUpKeyDown = true;
				break;
 
				case 39:
				bRightKeyDown = true;
				break;
 
				case 40:
				bDownKeyDown = true;
				break;
			}
		}
 
		private function keyUpHandler ( KBE:KeyboardEvent ) : void
		{
			switch ( KBE.keyCode )
			{
				case 37:
				bLeftKeyDown = false;
				break;
 
				case 38:
				bUpKeyDown = false;
				break;
 
				case 39:
				bRightKeyDown = false;
				break;
 
				case 40:
				bDownKeyDown = false;
				break;
			}
		}
 
		private function onEnterFrameHandler ( E:Event ) : void
		{
			if ( bLeftKeyDown )
			{
				GameShip.x -= 5;
			}
 
			if ( bUpKeyDown )
			{
				GameShip.y -= 5;
			}
 
			if ( bRightKeyDown )
			{
				GameShip.x += 5;
			}
 
			if ( bDownKeyDown )
			{
				GameShip.y += 5;
			}
		}
	}
}

Line 7: Import the Event class so I can use ENTER_FRAME

Lines 13-16: Setup 4 boolean variables, one to represent each direction of the ship.

Line 26: Added an event listener to tell when a key comes up.

Line 27: Added an event listener to act as the onEnterFrame.

Lines 30-51: Fixed my switch statement to now correspond with my boolean values and set them equal to true when the key is down. (Note: there is no Key.IsDown in AS3. You essentially have to do it yourself)

Lines 53-73: Switching the boolean values for when the key comes up.

Lines 75-97: Using the boolean values to add to the position of the ship in the onEnterFrameHandler. ENTER_FRAME is essentially something that is checked every frame, so if your framerate is 12, this function will be run 12 times/second.

Speed and Acceleration:

The ship is moving better now, but is still extremely slow and only moves at a constant speed. In real life the ship would not jump from zero to 60 instantly. It would accelerate its speed.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package
{
	import flash.display.Sprite;
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.events.KeyboardEvent;
	import flash.events.Event;
 
	public class Main extends Sprite
	{
		private var GameShip:Ship;
 
		private var bLeftKeyDown:Boolean;
		private var bUpKeyDown:Boolean;
		private var bRightKeyDown:Boolean;
		private var bDownKeyDown:Boolean;
 
		private var nPower:Number = 1;
		private var nSpeedX:Number = 0;
		private var nSpeedY:Number = 0;
 
		public function Main ( ) : void
		{
			GameShip = new Ship ( );
			this.addChild(GameShip);
			GameShip.x = stage.stageWidth/2;
			GameShip.y = stage.stageHeight - 50;
 
			stage.addEventListener ( KeyboardEvent.KEY_DOWN, keyDownHandler );
			stage.addEventListener ( KeyboardEvent.KEY_UP, keyUpHandler );
			stage.addEventListener ( Event.ENTER_FRAME, onEnterFrameHandler );
		}
 
		private function keyDownHandler ( KBE:KeyboardEvent ) : void
		{
			switch ( KBE.keyCode )
			{
				case 37:
				bLeftKeyDown = true;
				break;
 
				case 38:
				bUpKeyDown = true;
				break;
 
				case 39:
				bRightKeyDown = true;
				break;
 
				case 40:
				bDownKeyDown = true;
				break;
			}
		}
 
		private function keyUpHandler ( KBE:KeyboardEvent ) : void
		{
			switch ( KBE.keyCode )
			{
				case 37:
				bLeftKeyDown = false;
				break;
 
				case 38:
				bUpKeyDown = false;
				break;
 
				case 39:
				bRightKeyDown = false;
				break;
 
				case 40:
				bDownKeyDown = false;
				break;
			}
		}
 
		private function onEnterFrameHandler ( E:Event ) : void
		{
			if ( bLeftKeyDown )
			{
				nSpeedX -= nPower;
			}
 
			if ( bUpKeyDown )
			{
				nSpeedY -= nPower;
			}
 
			if ( bRightKeyDown )
			{
				nSpeedX += nPower;
			}
 
			if ( bDownKeyDown )
			{
				nSpeedY += nPower;
			}
 
			GameShip.x += nSpeedX;
			GameShip.y += nSpeedY;
		}
	}
}

Lines 18-20: Made three class variables to keep track of the speed in the x direction, speed in the y direction, and the another variable to act as my constant speed at which the ship will accelerate.

Lines 80-98: Now we have a speed for for each direction of the ship. Saving the speed as a variable is also important because now Flash can remember what the speed was the ship was going. Every enter frame, if the right key is down, it will add one to the speed. The next enter frame, the speed will still be the same and the ship will continue at that constant speed.

Lines 100-101: Adding the speeds to the x and y positions of the ship.

Friction and Speed Limit:

Now our ship is going to move forever. In real life, once the ship stops moving it should slowly decelerate and eventually stop. Also, for good measure, I am going to impose a speed limit on the ship so that the player can’t go above a certain speed.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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
130
package
{
	import flash.display.Sprite;
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.events.KeyboardEvent;
	import flash.events.Event;
 
	public class Main extends Sprite
	{
		private var GameShip:Ship;
 
		private var bLeftKeyDown:Boolean;
		private var bUpKeyDown:Boolean;
		private var bRightKeyDown:Boolean;
		private var bDownKeyDown:Boolean;
 
		private var nPower:Number = 1;
		private var nSpeedX:Number = 0;
		private var nSpeedY:Number = 0;
		private var nFriction:Number = .95;
 
		public function Main ( ) : void
		{
			GameShip = new Ship ( );
			this.addChild(GameShip);
			GameShip.x = stage.stageWidth/2;
			GameShip.y = stage.stageHeight - 50;
 
			stage.addEventListener ( KeyboardEvent.KEY_DOWN, keyDownHandler );
			stage.addEventListener ( KeyboardEvent.KEY_UP, keyUpHandler );
			stage.addEventListener ( Event.ENTER_FRAME, onEnterFrameHandler );
		}
 
		private function keyDownHandler ( KBE:KeyboardEvent ) : void
		{
			switch ( KBE.keyCode )
			{
				case 37:
				bLeftKeyDown = true;
				break;
 
				case 38:
				bUpKeyDown = true;
				break;
 
				case 39:
				bRightKeyDown = true;
				break;
 
				case 40:
				bDownKeyDown = true;
				break;
			}
		}
 
		private function keyUpHandler ( KBE:KeyboardEvent ) : void
		{
			switch ( KBE.keyCode )
			{
				case 37:
				bLeftKeyDown = false;
				break;
 
				case 38:
				bUpKeyDown = false;
				break;
 
				case 39:
				bRightKeyDown = false;
				break;
 
				case 40:
				bDownKeyDown = false;
				break;
			}
		}
 
		private function onEnterFrameHandler ( E:Event ) : void
		{
			if ( bLeftKeyDown )
			{
				if ( nSpeedX > -10 )
				{
					nSpeedX -= nPower;
				}
			}
 
			if ( bUpKeyDown )
			{
				if ( nSpeedY > -10 )
				{
					nSpeedY -= nPower;
				}
			}
 
			if ( bRightKeyDown )
			{
				if ( nSpeedX < 10 )
				{
					nSpeedX += nPower;
				}
			}
 
			if ( bDownKeyDown )
			{
				if ( nSpeedY < 10 )
				{
					nSpeedY += nPower;
				}
			}
 
			GameShip.x += nSpeedX;
			GameShip.y += nSpeedY;
 
			nSpeedX *= nFriction;
			nSpeedY *= nFriction;
 
			if ( nSpeedX * nSpeedX < .001 )
			{
				nSpeedX = 0;
			}
 
			if ( nSpeedY * nSpeedY < .001 )
			{
				nSpeedY = 0;
			}
		}
	}
}

Line 21: New variable called nFriction

Lines 81-111: Imposing the new speed limits on the ship. I wrote some if statements making sure the speed was below or above where I wanted it to be. Remember to keep your positive and negative directions straight.

Lines 116-117: Putting friction on the ship. I made nFriction = .95. Think about the math for a second if you don’t understand. 1.) 1 * .95 = .95 2.) .95 * .95 = 90.25 and so on… Everytime the enter frame goes through, the speed will be only 95% as strong as it was the previous time. This will slow down our ship slowly. The lower the value you use for friction, the faster your ship will slow down.

Lines 119-127: To save your computer from doing needless calculations, I made an if statement that looks to see if the speed is extremely small. If the speed is extremely small, Flash sets the speed to 0 and stops the ship from moving. If you didn’t do this your ship would still be moving and Flash would still be doing needless calculations forever.

The Bounds:

So the last problem with the ship is the bounds. It can go off the screen. This is a pretty easy fix.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package
{
	import flash.display.Sprite;
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.events.KeyboardEvent;
	import flash.events.Event;
 
	public class Main6 extends Sprite
	{
		private var GameShip:Ship;
 
		private var bLeftKeyDown:Boolean;
		private var bUpKeyDown:Boolean;
		private var bRightKeyDown:Boolean;
		private var bDownKeyDown:Boolean;
 
		private var nPower:Number = 1;
		private var nSpeedX:Number = 0;
		private var nSpeedY:Number = 0;
		private var nFriction:Number = .95;
 
		public function Main6 ( ) : void
		{
			GameShip = new Ship ( );
			this.addChild(GameShip);
			GameShip.x = stage.stageWidth/2;
			GameShip.y = stage.stageHeight - 50;
 
			stage.addEventListener ( KeyboardEvent.KEY_DOWN, keyDownHandler );
			stage.addEventListener ( KeyboardEvent.KEY_UP, keyUpHandler );
			stage.addEventListener ( Event.ENTER_FRAME, onEnterFrameHandler );
		}
 
		private function keyDownHandler ( KBE:KeyboardEvent ) : void
		{
			switch ( KBE.keyCode )
			{
				case 37:
				bLeftKeyDown = true;
				break;
 
				case 38:
				bUpKeyDown = true;
				break;
 
				case 39:
				bRightKeyDown = true;
				break;
 
				case 40:
				bDownKeyDown = true;
				break;
			}
		}
 
		private function keyUpHandler ( KBE:KeyboardEvent ) : void
		{
			switch ( KBE.keyCode )
			{
				case 37:
				bLeftKeyDown = false;
				break;
 
				case 38:
				bUpKeyDown = false;
				break;
 
				case 39:
				bRightKeyDown = false;
				break;
 
				case 40:
				bDownKeyDown = false;
				break;
			}
		}
 
		private function onEnterFrameHandler ( E:Event ) : void
		{
			if ( bLeftKeyDown )
			{
				if ( nSpeedX > -10 )
				{
					nSpeedX -= nPower;
				}
			}
 
			if ( bUpKeyDown )
			{
				if ( nSpeedY > -10 )
				{
					nSpeedY -= nPower;
				}
			}
 
			if ( bRightKeyDown )
			{
				if ( nSpeedX < 10 )
				{
					nSpeedX += nPower;
				}
			}
 
			if ( bDownKeyDown )
			{
				if ( nSpeedY < 10 )
				{
					nSpeedY += nPower;
				}
			}
 
			GameShip.x += nSpeedX;
			GameShip.y += nSpeedY;
 
			nSpeedX *= nFriction;
			nSpeedY *= nFriction;
 
			if ( nSpeedX * nSpeedX < .001 )
			{
				nSpeedX = 0;
			}
 
			if ( nSpeedY * nSpeedY < .001 )
			{
				nSpeedY = 0;
			}
 
			if ( GameShip.x + GameShip.width/2 > stage.stageWidth )
			{
				GameShip.x = stage.stageWidth - GameShip.width/2;
				nSpeedX = 0;
			}
 
			if ( GameShip.x - GameShip.width/2 < 0 )
			{
				GameShip.x = 0 + GameShip.width/2;
				nSpeedX = 0;
			}
 
			if ( GameShip.y + GameShip.height/2 > stage.stageHeight )
			{
				GameShip.y = stage.stageHeight - GameShip.height/2;
				nSpeedY = 0;
			}
 
			if ( GameShip.y - GameShip.height/2 < 0 )
			{
				GameShip.y = 0 + GameShip.height/2;
				nSpeedY = 0;
			}
		}
	}
}

Lines 129-151: This looks a lot more complicated than it is. What it is doing is checking where the ship is, seeing if it is over the stage size in all four directions, and if it is, stops the ship from moving and sets the ship to the edge of the screen. The extra stuff about the GameShip.width/2 and GameShip.height/2 is just to make the ship not go off the screen at all. If you didn’t have that, half the ship would go off the screen because the registration point is in the middle of the ship. Take it away and see what happens if you don’t know what I mean.

Well, that is all for this tutorial. I hope you found it helpful. If you are confused or want to ask some questions, please feel free to comment. I will answers all questions no matter what they are.

Thanks for reading. Here is the source for this tutorial. It is broken up into 6 files and each numbered file corresponds with the SWF on this page.

Trackback URI | Comments RSS

Leave a Reply