AS3 Avoider Game Tutorial, Part 7: Keyboard Control

by Michael James Williams on February 17, 2009 · 258 comments

in Avoider Game Base,Tutorial

In this part of my AS3 and Flash CS3 conversion of Frozen Haddock’s avoider game tutorial, we’ll add keyboard controls. Don’t worry, we’ll keep the code separate so that it won’t interfere with the mouse controls we’ve already put in!

Click the image below to see how this will play:

screenshot

If you’ve not been following the tutorial, grab the zip file of the game so far here and extract it somewhere. Otherwise, copy the files you’ve been working on so far to a new folder, as usual.

Open the FLA file, and let’s get started.

Switching Control Schemes

Rather than removing the mouse controls entirely, let’s set things up so that we can switch between the two control schemes easily. Open AvoiderGame.as, and create a new Boolean variable at the class level named useMouseControl:

?View Code ACTIONSCRIPT3
8
9
10
11
12
13
14
public class AvoiderGame extends MovieClip 
{
	public var army:Array;
	public var enemy:Enemy;
	public var avatar:Avatar;
	public var gameTimer:Timer;
	public var useMouseControl:Boolean;

Remember, a Boolean is a variable that can only be one of two values: true or false. We’re going to use it as a “toggle”; if it’s true, mouse controls will work and keyboard controls won’t; if it’s false, keyboard controls will work and mouse controls won’t.

Since we haven’t written the keyboard control code yet, let’s set it to true so that we can test it out. The constructor is a fine place to do this:

?View Code ACTIONSCRIPT3
16
17
18
public function AvoiderGame() 
{
	useMouseControl = true;

Since useMouseControl is defined at the class level, it’ll be available throughout AvoiderGame.

At the moment, there are only two places where we’re referring to the mouse’s position in code. The first is in the constructor, where we set the initial position of the avatar to be wherever the cursor is:

?View Code ACTIONSCRIPT3
25
26
27
28
avatar = new Avatar();
addChild( avatar );
avatar.x = mouseX;
avatar.y = mouseY;

If the player’s not using the mouse to control the game, it’s going to be pretty annoying for them to have the avatar start out wherever the mouse happens to be. Let’s change that:

?View Code ACTIONSCRIPT3
25
26
27
28
29
30
31
32
33
34
35
36
avatar = new Avatar();
addChild( avatar );
if ( useMouseControl )
{
	avatar.x = mouseX;
	avatar.y = mouseY;
}
else
{
	avatar.x = 200;
	avatar.y = 250;
}

The code in the else section is only going to be run if the player is using keyboard control, and will place the avatar at the bottom-centre of the screen (adjust the numbers depending on what you think is best).

Before we test this, let’s change the other bit of code that references the mouse. It’s in the onTick() function and it’s exactly the same:

?View Code ACTIONSCRIPT3
54
55
avatar.x = mouseX;
avatar.y = mouseY;

Not surprisingly, our change will be very similar to before:

?View Code ACTIONSCRIPT3
54
55
56
57
58
59
60
61
62
if ( useMouseControl )
{
	avatar.x = mouseX;
	avatar.y = mouseY;
}
else
{
	//no keyboard code yet!
}

(Remember, line 61 is a comment and will be ignored by Flash; it’s just there as a reminder to us.)

If you save this and run it… well, you won’t see anything different, because we’ve set useMouseControl to true. That’s good, it means we can do whatever we like regarding keyboard control and it won’t mess up our existing mouse control code.

Change useMouseControl to false (in the constructor) and run it again.

screenshot

You’ll find the avatar starts at the bottom-centre of the screen and cannot be moved by the mouse. Great! Well, not so great for the player. But we’ll fix that.

Going Down

Remember when we first programmed the Enemy, and wrote the function moveDownABit()? By increasing the y-position of the enemy a little bit every tick, we simulated downwards motion. Let’s use the same strategy for the Avatar. Open up Avatar.as. It’s almost entirely empty — how exciting:

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
10
11
package 
{
	import flash.display.MovieClip;
	public class Avatar extends MovieClip 
	{
		public function Avatar() 
		{
 
		}
	}
}

Add the new function:

?View Code ACTIONSCRIPT3
6
7
8
9
10
11
12
13
14
public function Avatar() 
{
 
}
 
public function moveDownABit():void
{
	y = y + 2;
}

Yep, this goes against what I said in the last part about hard-coding values. Don’t worry, we’ll change it soon.

The enemy objects have their movement functions called exactly once per tick. We need to call the appropriate movement functions for the avatar once per tick… but how do we know when it’s appropriate?

Ideally, we’d do something like this (in the onTick() function):

?View Code ACTIONSCRIPT3
54
55
56
57
58
59
60
61
62
63
64
65
if ( useMouseControl )
{
	avatar.x = mouseX;
	avatar.y = mouseY;
}
else
{
	if ( downKeyIsBeingPressed )
	{
		avatar.moveDownABit();
	}
}

In AS2 we could have done exactly that — but not in AS3. Now we’re living in the futuristic world of Events, and we have to do a little more to make this work.

You see, we can’t detect whether a given key is being pressed at a given time — that functionality is gone. But with event listeners, we can detect when a given key has been pushed down, and we can also detect when a given key has been lifted up again. If we have detected that a key has been pushed down and we have not yet detected that the same key has been lifted up, well, it’s a pretty safe bet that the key is being pushed down at that very moment, right?

[If this isn't clear, imagine that every time you press the B key, your computer says aloud "the B key has just been pressed", and every time you take your finger off the B key, your computer says "the B key is no longer being pressed". Someone listening to your computer would have a pretty good idea of whether or not you were pushing the B key even if they weren't looking at your hands.]

Enough talk. Let’s get the code in.

First, we need another Boolean to take note of whether the Down key is currently being pressed. Let’s call it downKeyIsBeingPressed. It needs to go in AvoiderGame.as, at the same places where we set up useMouseControl:

?View Code ACTIONSCRIPT3
14
15
16
17
18
19
20
public var useMouseControl:Boolean;
public var downKeyIsBeingPressed:Boolean;
 
public function AvoiderGame() 
{
	downKeyIsBeingPressed = false;
	useMouseControl = false;

(I’m assuming here that the player isn’t holding down the Down key as he starts the game.)

Now we need to detect when the player is pressing and releasing keys. You will probably not be surprised to find that we use event listeners for this. This should all be very simple to do, but unfortunately (and despite keyboard control being a Very Useful Feature for a lot of applications) Flash seems to go out of its way to make things confusing. Please bear with me through this next section, it’s not hard, just irritating :)

Flash vs. Developers

Let’s start by adding the event listeners. Add these lines to the end of the AvoiderGame.as constructor function:

?View Code ACTIONSCRIPT3
44
45
addEventListener( KeyboardEvent.KEY_DOWN, onKeyPress );
addEventListener( KeyboardEvent.KEY_UP, onKeyRelease );

Guess what? Yep, Flash needs to be told about KeyboardEvent, so import it at the top:

?View Code ACTIONSCRIPT3
3
4
5
6
7
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.ui.Mouse;
import flash.events.KeyboardEvent;

First we’ll create the onKeyPress event listener, which will be triggered whenever a key is pushed down:

?View Code ACTIONSCRIPT3
49
50
51
52
public function onKeyPress( keyboardEvent:KeyboardEvent ):void
{
 
}

(Remember to create this outside of the constructor function but inside the class.)

How do we know which key is being pressed? Well, every key has a unique ID number, called a key code, and the event object stores the key code of whichever key triggered the event. Obviously it would be inconvenient if we had to remember every single ID, so Flash helps us out by giving us a class, Keyboard, that stores all these codes.

Of course, we have to import it:

?View Code ACTIONSCRIPT3
3
4
5
6
7
8
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.ui.Mouse;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;

Go back to the onKeyPress event handler and add the following:

?View Code ACTIONSCRIPT3
50
51
52
53
54
55
56
public function onKeyPress( keyboardEvent:KeyboardEvent ):void
{
	if ( keyboardEvent.keyCode == Keyboard.DOWN )
	{
		downKeyIsBeingPressed = true;
	}
}

If you’re using Flash to write your AS files, then as soon as you type Keyboard. you’ll see a big list of all the different keys available appear.

The onKeyRelease event listener is very similar:

?View Code ACTIONSCRIPT3
58
59
60
61
62
63
64
public function onKeyRelease( keyboardEvent:KeyboardEvent ):void
{
	if ( keyboardEvent.keyCode == Keyboard.DOWN )
	{
		downKeyIsBeingPressed = false;
	}
}

Obviously it’s very important to have downKeyIsBeingPressed set to false here and true above.

Alright, so, in theory we should now be able to tell whether the Down key is currently being pressed from any point within AvoiderGame. This means we can add in our ideal code from earlier to the onTick() function:

?View Code ACTIONSCRIPT3
77
78
79
80
81
82
83
84
85
86
87
88
if ( useMouseControl )
{
	avatar.x = mouseX;
	avatar.y = mouseY;
}
else
{
	if ( downKeyIsBeingPressed )
	{
		avatar.moveDownABit();
	}
}

If you save it and run it this will not work. Sorry. We have to make a couple of changes first.

For one thing, Keyboard Event listeners have to be added to the stage. To quote the AS3 LiveDocs: “The Stage class represents the main drawing area. The Stage represents the entire area where Flash® content is shown.”

Simple enough. Go back to the constructor function and change the addEventListener calls from this:

?View Code ACTIONSCRIPT3
47
48
addEventListener( KeyboardEvent.KEY_DOWN, onKeyPress );
addEventListener( KeyboardEvent.KEY_UP, onKeyRelease );

to this:

?View Code ACTIONSCRIPT3
47
48
stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyPress );
stage.addEventListener( KeyboardEvent.KEY_UP, onKeyRelease );

Will this work now? No, we’ll get an error:

TypeError: Error #1009: Cannot access a property or method of a null object reference.

The problem is, stage is actually null at this point. Why? Well, an object only has access to stage if it’s been addChild-ed to the document class, or to another object that has been addChild-ed to the document class or… etc. But look at the code in DocumentClass.as:

?View Code ACTIONSCRIPT3
40
41
42
43
44
playScreen = new AvoiderGame();
playScreen.addEventListener( AvatarEvent.DEAD, onAvatarDeath );
playScreen.x = 0;
playScreen.y = 0;
addChild( playScreen );

The AvoiderGame() constructor function — and therefore the stage.addEventListener() lines — is run when new AvoiderGame() is run. But the addChild( playScreen ) line — which is required for playScreen to actually have a stage — isn’t run until after that point.

We get around this by using another event listener. This one is going to be triggered when that addChild( playScreen ) line is called. We can then add the stage.addEventListener() lines within that event handler. Confusing? Let’s write the code, it’ll make it clearer.

First, in AvoiderGame.as, replace

?View Code ACTIONSCRIPT3
47
48
stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyPress );
stage.addEventListener( KeyboardEvent.KEY_UP, onKeyRelease );

with

?View Code ACTIONSCRIPT3
46
addEventListener( Event.ADDED_TO_STAGE, onAddToStage );

(Don’t delete the onKeyPress and onKeyRelease event handler functions, we’ll need them later!)

Naturally we need to import this Event class…

?View Code ACTIONSCRIPT3
3
4
5
6
7
8
9
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.ui.Mouse;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.events.Event;

Now, create a new event handler for this Event.ADDED_TO_STAGE event:

?View Code ACTIONSCRIPT3
50
51
52
53
54
public function onAddToStage( event:Event ):void
{
	stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyPress );
	stage.addEventListener( KeyboardEvent.KEY_UP, onKeyRelease );
}

Save it and run it. Hooray, it works!

Although… try pressing any of the other keys on the keyboard while the game is running. You’ll probably notice the mouse flashing to different symbols. If you have the FLA open, rather than an AS file, you’ll be able to see the different buttons in the toolbar being selected as you press different letter keys.

This is another of Stephen Calender’s obstacles for Flash game development, and it’s incredibly irritating if you want to use keys that also happen to be used by Flash. Fortunately, there is a solution. When your game is running, click Control > Disable Keyboard Shortcuts:

screenshot

Voilà, no more problems.

[Jake let me know that this behaviour still exists in CS4 -- but luckily, so does the solution.]

Four-Way Movement

It’s now pretty simple to set the code up to detect other keys. Just take what we’ve already done and multiply it.

Class variables:

?View Code ACTIONSCRIPT3
17
18
19
20
21
public var useMouseControl:Boolean;
public var downKeyIsBeingPressed:Boolean;
public var upKeyIsBeingPressed:Boolean;
public var leftKeyIsBeingPressed:Boolean;
public var rightKeyIsBeingPressed:Boolean;

Constructor function:

?View Code ACTIONSCRIPT3
23
24
25
26
27
28
public function AvoiderGame() 
{
	downKeyIsBeingPressed = false;
	upKeyIsBeingPressed = false;
	leftKeyIsBeingPressed = false;
	rightKeyIsBeingPressed = false;

onKeyPress event handler:

?View Code ACTIONSCRIPT3
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
public function onKeyPress( keyboardEvent:KeyboardEvent ):void
{
	if ( keyboardEvent.keyCode == Keyboard.DOWN )
	{
		downKeyIsBeingPressed = true;
	}
	else if ( keyboardEvent.keyCode == Keyboard.UP )
	{
		upKeyIsBeingPressed = true;
	}
	else if ( keyboardEvent.keyCode == Keyboard.LEFT )
	{
		leftKeyIsBeingPressed = true;
	}
	else if ( keyboardEvent.keyCode == Keyboard.RIGHT )
	{
		rightKeyIsBeingPressed = true;
	}
}

I’ll leave you to figure out the onKeyRelease event handler :)

Perhaps you are thinking that I am a bit of a hypocrite, because back in Part 2 I said that it was bad to copy and paste code like that. Fair point! Actually, it would be much better to use an array of Booleans to store the states of every single key. I encourage you to have a go at that yourself (I did leave some hints in the comments of one of the earlier parts, if you get stuck). Alternatively, there’s a great piece of code here that’ll handle it all for you, the credit for which goes to the ever-excellent senocular. (If you’re having trouble getting this code to work, Monkeyman has written a great comment explaining what to do here.)

Now, I don’t fancy having four functions, moveDownABit(), moveUpABit(), etc., so I’m going to suggest we generalise moveDownABit(), just as we did with the Enemy code.

Go back to Avatar.as and change your moveDownABit() function to this:

?View Code ACTIONSCRIPT3
11
12
13
14
15
public function moveABit( xDistance:Number, yDistance:Number ):void
{
	x += xDistance;
	y += yDistance;
}

We now need to pass the directions through from AvoiderGame.as, so reopen that file. Start by changing what we already had, from this:

?View Code ACTIONSCRIPT3
109
110
111
112
if ( downKeyIsBeingPressed )
{
	avatar.moveDownABit();
}

to this:

?View Code ACTIONSCRIPT3
109
110
111
112
if ( downKeyIsBeingPressed )
{
	avatar.moveABit( 0, 3 );
}

That’ll work, but we shouldn’t be writing “3″ explicitely, should we? Try this instead:

?View Code ACTIONSCRIPT3
109
110
111
112
if ( downKeyIsBeingPressed )
{
	avatar.moveABit( 0, 1 );
}

And in Avatar.as:

?View Code ACTIONSCRIPT3
11
12
13
14
15
16
public function moveABit( xDistance:Number, yDistance:Number ):void
{
	var baseSpeed:Number = 3;
	x += ( xDistance * baseSpeed );
	y += ( yDistance * baseSpeed );
}

See what we’re doing? If not, let’s add in the other three directions and make it a bit clearer. Go back to AvoiderGame.as:

?View Code ACTIONSCRIPT3
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
if ( downKeyIsBeingPressed )
{
	avatar.moveABit( 0, 1 );
}
else if ( upKeyIsBeingPressed )
{
	avatar.moveABit( 0, -1 );
}
else if ( leftKeyIsBeingPressed )
{
	avatar.moveABit( -1, 0 );
}
else if ( rightKeyIsBeingPressed )
{
	avatar.moveABit( 1, 0 );
}

You see, the two parameters now define the direction of movement, rather than the speed. Speed is defined inside the Avatar class, which makes sense (and also follows the standard set by the Enemy class).

However, you can affect the relative speed of the avatar from the AvoiderGame class. For example, you could make WSAD the “walking” controls, which make the avatar move at half the speed, simply by adding lines like this:

?View Code ACTIONSCRIPT3
if ( sKeyIsBeingPressed )
{
	avatar.moveABit( 0, 0.5 );
}

Setting Some Boundaries

If you run the game now, you’ll see that it’s possible to move the avatar outside of the playing field, and therefore avoid all the enemies entirely!

To get round this, all we have to do is write some code to check, every tick, whether the avatar somewhere it shouldn’t be, and move it back into the playing field if so.

I think the best place for this is in AvoiderGame.as, in the onTick() function, immediately after all the code we’ve just written. Let me demonstrate with this code snippet:

?View Code ACTIONSCRIPT3
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
if ( useMouseControl )
{
	avatar.x = mouseX;
	avatar.y = mouseY;
}
else
{
	if ( downKeyIsBeingPressed )
	{
		avatar.moveABit( 0, 1 );
	}
	else if ( upKeyIsBeingPressed )
	{
		avatar.moveABit( 0, -1 );
	}
	else if ( leftKeyIsBeingPressed )
	{
		avatar.moveABit( -1, 0 );
	}
	else if ( rightKeyIsBeingPressed )
	{
		avatar.moveABit( 1, 0 );
	}
}
 
//we should check the avatar's position here
//and move it if we need to
 
var avatarHasBeenHit:Boolean = false;
for each ( var enemy:Enemy in army ) 
{
	enemy.moveABit();

Where isn’t the avatar allowed? Let’s start with horizontal movement: the avatar can’t go left of the playing field. Now, we know that the left side of the play screen has an x-coordinate of zero (check the diagram in the first part of this tutorial for a reminder). So if the avatar’s x-coordinate is less than zero, it must be to the left of the play screen:

?View Code ACTIONSCRIPT3
139
140
141
142
if ( avatar.x < 0 )
{
	//avatar is left of play screen
}

What shall we do about it? It’s pretty simple — we just move the avatar back to the left edge:

?View Code ACTIONSCRIPT3
139
140
141
142
if ( avatar.x < 0 )
{
	avatar.x = 0;
}

Actually, because the avatar’s registration point is right in its centre, half-way across its width, this will let the avatar get half-way out of the screen:

screenshot

You can keep it like this if you like, but I’d rather make sure the whole avatar was inside the screen. Fortunately this is easy too; we can just change our code like this:

?View Code ACTIONSCRIPT3
139
140
141
142
if ( avatar.x < ( avatar.width / 2 ) )
{
	avatar.x = avatar.width / 2;
}

If that’s confusing, just bear in mind that avatar.x refers to the x-coordinate of the centre of the avatar. The centre is, naturally, half a width away from the left-hand side. (Of course, if your avatar’s registration point isn’t centred, you’ll have to measure the distance yourself.)

This makes the avatar stop at the left side of the screen as if it were a wall:

screenshot

The other three directions can be added similarly:

?View Code ACTIONSCRIPT3
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
if ( avatar.x < ( avatar.width / 2 ) )
{
	avatar.x = avatar.width / 2;
}
if ( avatar.x > 400 - ( avatar.width / 2 ) )
{
	avatar.x = 400 - ( avatar.width / 2 );
}
if ( avatar.y < ( avatar.height / 2 ) )
{
	avatar.y = avatar.height / 2;
}
if ( avatar.y > 300 - ( avatar.height / 2 ) )
{
	avatar.y = 300 - ( avatar.height / 2 );
}

The numbers 400 and 300 are the width and height of my game. Bonus points for you if you use the soft-coding tip I talked about in Part 6 instead ;)

Challenges

We’re getting to the point now where you understand a lot of concepts, and it’s actually more beneficial for you to have a go at using them yourself rather than having someone else tell you every single step to take. If you’re lacking inspiration, here are some ideas to get you started.

How about changing the menu screen to have two buttons — one for mouse control, and one for keyboard control? Hint: pass the value of useMouseControl through the AvoiderGame() constructor, like we do with the enemy’s position in the Enemy() constructor.

You might have found that the game is considerably harder with keyboard controls than with mouse controls. How about altering the rate at which enemies appear if the player is using the keyboard?

You’ve got four-way movement sorted; now how about eight-way movement? Hint: you can check if ( ( downKeyIsPressed ) && ( leftKeyIsPressed ) ). Be careful — the Pythagorean Theorem tells us that if you move three pixels down and three pixels left within a single tick, you’ll travel further (and therefore faster) than if you just move three pixels down or three pixels left. How can you get around that? UPDATE: Rasmus Wriedt Larsen wrote a tutorial on doing exactly this. Check it out here.

It’s always irritating to have to switch between keyboard and mouse. Can you make it so that the Start and Restart buttons can be pressed by hitting the space bar?

Don’t forget to have a go at making an array of booleans to hold the state of all your keys at once, or to use senocular’s KeyboardObject class, as mentioned above.

If you’d like a hand with any of these challenges, stick a note in the comments box below. If you’ve got any of your own, I’d love to hear them :)

Wrapping Up

That’s it for this week. As usual you can grab the zip file here.

In Part 8, we’ll add a preloader, an essential requirement for any Flash game.

{ 258 comments… read them below or add one }

Kevin February 9, 2012 at 7:11 pm

Hey, i was just wondering if you could help me with a problem, well i am trying to do the challenge that is to “restart” a game by pressing space, well i worked it out and was fine until when i click “space” it restarts, but my avatar won’t be able to do anything or move, and if i click any other key then space it restarts on and on…

Is the problem, cause i have the defined keys “w , a , s , d , down , up , right , left” in the AvoiderGame.as , or should be a code that limits the usage of other keys or that helps stops the usage of “w, a, s ,d …..” in other places then “PlayScreen” ? If so please help me :) And Thanks.

P.S:

Here’s all my “GameOverScreen.as” :

 package 
{
    import flash.display.MovieClip;
    import flash.display.SimpleButton;
    import flash.text.TextField;
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.ui.Mouse;

public class GameOverScreen extends MovieClip 
{
    public var spaceKeyIsBeingPressed:Boolean;

public function GameOverScreen() 
{
    spaceKeyIsBeingPressed = false;
    Mouse.hide();
    restartButton.addEventListener( Event.ADDED_TO_STAGE, onAddToStage );
}

public function onAddToStage( event:Event ):void
{
    stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyPress );
    stage.addEventListener( KeyboardEvent.KEY_UP, onKeyRelease );
} 

public function onKeyPress( keyboardEvent:KeyboardEvent ):void 
{
    dispatchEvent( new NavigationEvent( NavigationEvent.RESTART ) );
}

public function onKeyRelease( keyboardEvent:KeyboardEvent ):void
{
    if ( keyboardEvent.keyCode == Keyboard.SPACE )
    { 
        spaceKeyIsBeingPressed = false;
    }
}
public function setFinalScore( scoreValue:Number ):void
{
    finalScore.text = scoreValue.toString();
}

public function setFinalClockTime( clockValue:Number ):void
{
    finalClockTime.text = Math.floor( clockValue / 1000 ).toString();
}

}

}

Argabo March 22, 2012 at 9:55 pm

Hi,
very helpful! I’ve learned so much from you during these turorials. I was coding in AS2 previously, but I’m interested in AS3 now.
I took up one of your challnges, here’s what i did:

public class AvoiderGame extends MovieClip
{
    public var army:Array;
    public var avatar:Avatar;
    public var gameTimer:Timer;
    public var useMouseControl:Boolean;
    public var freq:Number;
    public var keyStates:Array; //this is my new array

In the constructor:

keyStates = new Array(false, false, false, false);
public function onKeyPress(keyboardEvent:KeyboardEvent):void
{
    keyStates[keyboardEvent.keyCode-37] = true;
}
public function onKeyRelease(keyboardEvent:KeyboardEvent):void
{
    keyStates[keyboardEvent.keyCode-37] = false;
}

And in the onTick function:

else
{
    if (keyStates[0])
    {
        avatar.moveABit(-1, 0)
    }
    if (keyStates[1])
    {
        avatar.moveABit(0, -1)
    }
    if (keyStates[2])
    {
        avatar.moveABit(1, 0)
    }
    if (keyStates[3])
    {
        avatar.moveABit(0, 1)
    }
}

Is it ok – more or less?

Lapys May 14, 2012 at 11:56 pm

Hiya Michael,

First off, great tutorials! They’re written so well, and they’re incredibly informative. I really appreciate the posts.

The only thing I haven’t understood so far is how putting the keys into an array of Booleans is very helpful. I can see it aiding us some when we’re checking for movement, ie (in our onTick function):

// keys is an array of Booleans
for each ( var key:Boolean in keys ) {
   if( keys[0] ) { //Move up }
   else if( keys[1] ) { //Move down }
   ...
   }

And, of course, we don’t have to make a brand new variable for each and every key we want functionality for: we can just push a new Boolean onto the array of keys.

But is that all it’s for? Does this have any affect on either the length of (in lines) or way we implement the onKeyPress or onKeyRelease functions? I guess I’m not having trouble so much with implementing the Booleans for each keys, as I am with figuring out why it’s helpful and, specifically, where it’s helpful. Any response would be awesome.

Thanks again for these great tutorials! I’m having a blast getting through them and I definitely will have to look at some of your other posts based on these.

Alphamazing June 10, 2012 at 1:15 am

Hey mate, i know almost every other person has said this already, but anyway i need to say it myself “Awesome tutorial man” i wanted to learn AS for a long while now, but couldnt find a tutorial as easy and fun to follow, so Thank a lot and keep up the good work… :)

Anyhow i have found myself stock in one of your challenges, creating an array of booleans, i have been giving it my all to grasp the concept of the “array” and even found a site with a fearly decent explanation wich helped me understand a lot better how they are meant to be used, but still i failed to understand where to beging in order to make an “array of booleans”.

My problem is, i dont understand how creating an array will help me from having to “copy and paste” codes in order to know whats happening with the keys. It doesnt matter how i look at it all that copy paste info needs to be somewhere in the code, and then i can feed it to the array, which by the way am not really so sure how to do since the one array i’ve made (army/Enemy) refers to a class.

I am really confused on how to start the array and its really bothering me since i’ve managed every other challenge before on my own ( except for the function to feed the enemy the avatars possition but i just didnt thik it was needed at the moment)

If there is any tip or direction you could provide it will be extreamly apreciated, no body has posted here in a while so i hope you still following this.

Thank you for the wonderfull tutorial i am really enjoying it :)

Joe August 18, 2012 at 11:35 am

Michael,

Thanks sooooo much for these tutorials!

Many flash tutorials lack quality control but yours are excellent and clear to follow – I am new to game development but have been inspired by the OUYA project. I am a creative in a non-creative industry and I love to find a release for my creativity – OUYA will be accessible to develop on and that got me inspired to challenge myself to releasing a game on the OUYA by the end of 2013 (maybe 2014!). The main challenge is I am a novice at coding and game making! But I have growth mindset and am going to give it a bash!

I have chosen to develop games on Flash to start with before transferring over to android and the OUYA SDK on release. I am finding your tutorials very helpful and have used the Avoider tutorial series as a base for designing my first flash game “Martin the Mouse and The Flying Cheese” …. catchy title I know! (Hopefully you will play it one day to see my take on your tutorial).

Problem is…. I have hit a snag and can’t seem to fix it!

I am controlling my Avatar’s (a mouse in a mini hot air ballon) movement with a pre-determined wind which adds 0.4 to the Avatar’s x value onTick. I also am adding a very basic and crude gravity effect to my Avatar which add 0.6 to it’s y value onTick. However, I want to provide the user with a ‘Gas’ button which will allow the Avatar to counteract the gravity and push the Avatar up the screen which will be activated by a keyboard press of ‘G’. The player will have to dodge flying seagulls as they attempt to reach a bit of cheese attached to a ballon (at the end of the level). Without the ‘Gas’ working my Avatar obviously drifts along and off the screen from its starting position… not great game play!

I have attempted to add a keyboard control as you outlined in the tutorial but I just can’t seem to get it to work. I am getting the following Complier Errors:

Line 23 1120: Access of undefined property downKeyisBeingPressed. **
Line 41 1120: Access of undefined property onAddToStage.
** and again on each line that downKeyisBeingPressed is used

I get the feeling I am being really stupid with this one and its a very simple solution to a coder being dumb…. can anyone help me with this one? Would be so appreciated that I will allow anyone that answers a free … yes FREE! … play on my final game – if that isn’t motivation for you I don’t know what is!

Joe

tomas October 5, 2012 at 5:54 am

yo lo le pude a si


package
{
import flash.display.MovieClip;
import flash.display.SimpleButton;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.ui.Mouse;
import flash.ui.Keyboard;
import flash.events.Event;
import flash.events.KeyboardEvent;

public class GameOverScreen extends MovieClip
{
    public var spaceKeyIsBeingPressed:Boolean;

public function GameOverScreen()
{
    spaceKeyIsBeingPressed = false;
    Mouse.show();
    restartButton.addEventListener( MouseEvent.CLICK, onClickRestart );
    addEventListener( Event.ADDED_TO_STAGE, onAddToStage );
}

public function onAddToStage( event:Event ):void
{
    stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyPress );
    stage.addEventListener( KeyboardEvent.KEY_UP, onKeyRelease );
}

public function onKeyPress( keyboardEvent:KeyboardEvent ):void
{
    if (keyboardEvent.keyCode == Keyboard.SPACE)
    {
        spaceKeyIsBeingPressed = true;
        dispatchEvent( new NavigationEvent( NavigationEvent.RESTART ) );
    }
}

public function onKeyRelease( keyboardEvent:KeyboardEvent ):void
{


    if (keyboardEvent.keyCode == Keyboard.SPACE)
    {
        spaceKeyIsBeingPressed = false;
    }
}


public function onClickRestart( mouseEvent:MouseEvent )
{
    dispatchEvent( new NavigationEvent( NavigationEvent.RESTART ) );
}

public function setFinalScore( scoreValue:Number ):void
{
    finalScore.text = scoreValue.toString();
}

public function setFinalClockTime( clockValue:Number ):void
{
    finalClockTime.text = Math.floor( clockValue / 1000 ).toString();
}

}

}

Tripy Fish May 9, 2013 at 12:56 am

Your tutorials are awesome Michael, really awesome. Thanks for putting in the time to create them. Until now, all my issues I have had have been easy to fix.
The problem I have is with the code: ” addEventListener( Event.ADDED_TO_STAGE, onAddToStage );”
It puts out these errors: 1180, Call to a possibly undefined method addEventListener
As well as: 1120, access of undefined property onAddToStage

Kerry June 18, 2013 at 8:42 pm

Sadly your link to Rasmus Wriedt Larsen’s tutorial doesn’t work anymore

Leave a Comment

Writing code? Write <pre> at the start and </pre> at the end to keep it looking neat.

Anti-Spam Protection by WP-SpamFree

Previous post:

Next post: