Keyboard input the right and wrong way

(Note: there does exist a drill 2 file with the wrong way illustrated. I decided I need not upload it (it's in the ZIP file though). You won't need it. So now my numbering is all off by one: drill_3 on page 2, etc.... Doh! Oh, well...)

There is a general principle to using flash events that I want you to keep in mind: to get continuous action, you need to use a continuous event. In Flash's event system, there are only a couple of these continuous events available, and the most important one is the ENTER_FRAME event, and that's the one we'll use. I'll have lots more to say about it soon.

But first, there is a little mistake that practically everyone makes when they first begin programming keyboard input for a game. That mistake is to combine commands to move your player with the events that get keyboard input. It's a natural mistake, because you would think there would be nothing wrong with this:

import flash.events.KeyboardEvent;

stage.addEventListener(KeyboardEvent.KEY_DOWN, stage_onKeyDown);

function stage_onKeyDown(event:KeyboardEvent):void {
	if(event.keyCode == 39) {
		player.x = player.x + 10;
	}
	if(event.keyCode == 37) {
		player.x = player.x - 10;
	}
}

Note that the above does NOT make use of ENTER_FRAME, which is a big part of its erroneous ways! It's correct that the event listener for the keyboard should be added to the stage, so that part is fine. The other correct parts are the if statements that sort out the keys being pressed. 39 is the code for the right arrow key, and 37 the left arrow key. The part that isn't correct is the idea of directly moving the player in response to those keypress events. The only reason this system works at all is because of something called the keyboard repeat rate.

In normal typing on your keyboard (in text editors, word processors, or just about any program on your computer), if you hold down a key, the keystroke will register once, then after an initial slight lag, the key will begin to repeat itself on and on. So what the above code is actually doing is using this keyboard repeating feature to provide the continuous action needed to move the player. The result is that the player moves once right away, then after an initial lag, the player starts moving. Probably this lag is the most undesirable part, but there is also the issue of not being able to control the speed of the continuous action in any way. It's not one of flash's events. The keyboard repeat rate is actually built in to the operating system! Anyway, here's how this wrong way looks in action:

Click on the above swf one time, then use the left and right arrow keys to move the player. Notice the lag? Isn't it horrible? By tying the keyboard events directly to the movement of the player, there's no way to take out this lag. Quick, let's figure out how to fix it!

Since you can't eliminate the keyboard repeat feature, you just need to find a way to work with it and around it. One answer I have found is to create a Boolean variable for each key you want to keep track of. Boolean variables, as you may know, are variables that can have a value of either true or false, and when you first declare them, they already have an initial (default) value of false. Then, when the user presses an arrow key, you assign the associated Boolean variable a value of true. When the user releases that key, you set the variable to false again.

Because the action of the keypress is only turning a variable to true, a person can hold down that key for as long as they want, because the only effect it's having now is it's setting the variable to true. Repeatedly setting the variable to true doesn't change it after the first time (you can't make it any MORE true, eh?), so we effectively absorb the keyboard repeat rate and tame it! So pressing and releasing a key will do nothing but turn a Boolean variable on and off, like a light switch. Meanwhile, we also add an event listener for ENTER_FRAME that tests to see if the value of this variable is true or not. If it is, move the player. If it isn't, don't:

import flash.events.KeyboardEvent;
import flash.events.Event;

var rightArrow:Boolean;
var leftArrow:Boolean;

stage.addEventListener(KeyboardEvent.KEY_DOWN, stage_onKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, stage_onKeyUp);
stage.addEventListener(Event.ENTER_FRAME, stage_onEnterFrame);

function stage_onKeyDown(event:KeyboardEvent):void {
	if(event.keyCode == 39) {
		rightArrow = true;
	}
	if(event.keyCode == 37) {
		leftArrow = true;
	}
}
function stage_onKeyUp(event:KeyboardEvent):void {
	if(event.keyCode == 39) {
		rightArrow = false;
	}
	if(event.keyCode == 37) {
		leftArrow = false;
	}
}
function stage_onEnterFrame(event:Event):void {
	if(rightArrow == true) {
		player.x += 10;
	}
	if(leftArrow == true) {
		player.x -= 10;
	}
}

And here's how this better version looks in action:

(Note: with keyboard stuff, you always have to click on the swf to give it focus. So you'll need to click on the above just once to get it working with the arrow keys). Now you can move the player back and forth with the right and left arrow keys without that ugly lag. Ahhh, much better!  The code is a bit more verbose, but shouldn't be too hard to understand. The keypresses and releases are just turning variables to true or false, and at the same time, the ENTER_FRAME event is moving the player based on whether those same variables are true or not.

I told you I'd have more to say about the ENTER_FRAME event. Well, here it is. I've always felt that this event was misnamed, but they had to call it something, and it had to be short and concise. But the name makes it sound like an event that fires if Flash's playhead enters a new frame, and that's not at all what it is. What it actually is, is an event that fires at the framerate of the movie, whether the playhead is moving or not. It fires even if there is only one frame in your movie. It's constant, like the ticking of a stopwatch. As soon as you add an event listener for it, your event listener will immediately start being called until you remove it again. In the above example, the ENTER_FRAME handler function is executing constantly. You don't see the effect unless you press one of the keys. But the function is still getting called repeatedly. It's just that unless a key is pressed, the two if statements continually fail.

ENTER_FRAME is something you should consider to be the heartbeat of your program. Sometimes it's called your "game loop." Everything that needs to happen continually needs to be controlled by this event somehow. Moving the player with the keys, moving the enemies down from the top of the screen, moving the bullets in the up direction, checking for collisions between the bullets and the enemies, and checking for collisions between the enemies and the player--all these things need continuous action, so they all need this continuous event to control them somehow. Don't worry if it sounds complicated. We'll keep taking it a step at a time!

The next things to do are to make the player stop at the edges of the screen, and to make it fire bullets! On to the next page!