As3: Event Basics
-------------------------
As3: Main
Let's say you just tried out my wonderful tile-based game mechanics tutorial, and you got the grid and all working. Now what? How do you make things move? How can you tell it to move to the mouse's position? What if you want something to happen every few seconds? What the hell does Event.ADDED_TO_STAGE mean when you start a new file in FlashDevelop and such?
Essentially, I want something to happen when something else happens.
In AS3, we use Events. An Event is when something happens. We use listeners that wait until the Event happens, and the listener calls a function that does stuff. Let's look at that ADDED_TO_STAGE junk.
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
The first line is needed so your game doesn't die before even starting. The second line is what we're more concerned about.
addEventListener
This is how we tell Flash to be on the look out for when the event happens. We add this listener to the main file because it doesn't need special attention. Some listeners get added to the stage, timers, sprites and movieclips, etc (more on that in a bit).
Event
The Event class. There are a lot of Event classes, but the important ones for the basics are Event, MouseEvent, TimerEvent, KeyboardEvent, and ProgressEvent.
.ADDED_TO_STAGE
This is the type of Event. What you want Flash to listen for. This code is telling Flash, "Hey, when you start to addChild stuff, hit me up."
, init
This is the function that you want to happen when Flash hits up the listener. When the listener finds out that stuff got added to the stage (ADDED_TO_STAGE), it runs the function init, which starts your game up.
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
(Ignore the "= null" for this, it's not needed except in special cases). This part is very important. Functions inside our Event listeners aren't normal functions. The listener passes in a parameter to our function, so we have to let it do so. Normal functions look like
stuff()
But an Event function needs
stuff(e:Event)
The "e" there can be whatever you'd like: e, event, evt; whatever suits you. This is a parameter/variable; the listener gives our function access to the Event's information. Since this "e" is a thing inside Flash, it needs a class to let the function know what is can do. "Event" is the class in this case, though it could also be MouseEvent, etc.
Earlier, I mentioned that there are a bunch of Events. All of the types are listed in the docs if you ever want to check. This will only list the very important ones.
MouseEvent is for when the mouse does stuff. When the mouse moves, moves over a thing, moves out of a thing, clicks, double clicks, etc, use this. The caveat to using these is that you have to tell Flash what object you want the events to apply to. For instance: you make a sprite, and you want the sprite to rotate when you click it. Well, you don't want the main class to rotate (if that's even possible...); so we have to tell Flash.
sprite.addEventListener(MouseEvent.CLICK, doStuff);
So now, if we click the sprite, it will call the doStuff function.
function doStuff(e:MouseEvent):void {
We can add this listener to multiple objects as well! If you want multiple things to rotate when you click each of them:
sprite.addEventListener(MouseEvent.CLICK, doStuff)
goose.addEventListener(MouseEvent.CLICK, doStuff)
player.addEventListener(MouseEvent.CLICK, doStuff)
stage.addEventListener(MouseEvent.CLICK, doStuff)
But if everything can use the same function, how to we tell the function which thing got clicked? Don't worry, Flash has you covered. Remember the "e," "event," or "evt" from earlier? Since that's now a variable inside our function, we have access to its information. Namely, the target and currentTarget properties.
e.target; e.currentTarget
e.target is a reference to the specific thing that got clicked. e.currentTarget will always return the thing that added the listener. For instance, if you had a ton of stuff that you wanted to rotate, you could simply add the listener to the stage, where everything is located, instead of to 100 sprites. e.target will tell you what sprite on the stage you clicked. e.currentTarget will give you the stage. This is because of a process called "bubbling," which is above the scope of this tutorial.
stage.addEventListener(MouseEvent.CLICK, doStuff);
function doStuff(e:MouseEvent):void {
trace(e.target); // if your mouse was actually over anything, it will trace out [object Sprite]
// if it was hovering over empty space, it'll trace out [object Stage]
trace(e.currentTarget); // will trace out [object Stage]
if (e.target !== stage) { //we don't want the stage to rotate when it's clicked, so exclude that
e.target.rotation += 45; // rotate whatever we clicked
}
}
TimerEvent is when we want stuff to happen regularly (once per second, half-second, etc). We add this to a timer object.
var timer:Timer = new Timer(1000);
timer.start();
timer.addEventListener(TimerEvent.TIMER, everySecond);
function everySecond(e:TimerEvent) { // function runs based on when timer finishes (once per second in this example)
KeyboardEvent is used to see which key got pressed or released. We use the keyCode property to check which key it is. This needs to be added to the stage since the main class flunked KeyboardEvent school and doesn't know how to handle it.
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUp);
function keyDown(e:KeyboardEvent):void {
if (e.keyCode == 37) trace("Left Button was pressed");
}
function keyUp(e:KeyboardEvent):void {
if (e.keyCode == 37) trace("Left Button was released");
}
The key - keyCode chart is here.
ProgressEvent is used when you load stuff to see how far along it is; this is only important since Preloaders use these. Not going to go into too much detail, but e.bytesLoaded / e.bytesTotal * 100 gives you the percent that has been loaded.
Event is for the basic stuff. ENTER_FRAME is probably the most used type as it's how to create loops: how to make your player constantly move, etc. If your game's frameRate is 30fps, ENTER_FRAME will call the function 30 times per second. The other type, of course, is ADDED_TO_STAGE (and REMOVED_FROM_STAGE).
addEventListener(Event.ENTER_FRAME, myLoop);
function myLoop(e:Event):void {
if(sprite.x < 600) sprite.x += 10; // moves the sprite 30 times per second
//notice the conditional inside the loop. you can put those, for loops, and everything else inside as well
If your game lags, it's because of this loop. I promise. A major point in coding is to minimize the stuff that goes in here. You shouldn't torture Flash by running your laggy, unoptimized code 30 times per second. But for the most part, you should be fine as long as you use common sense when you code.
And finally, if you want to get rid of a listener:
stage.removeEventListener(MouseEvent.CLICK, doStuff)
The syntax is the exact same as addEventListener. This tells the listener that it's overstayed its welcome and that it's time to go. Clicking will no longer call doStuff. But then you can add the listener back later.
You can't do anything in a game without events. Understanding them will help you make your stuff awesome.
Thanks for reading :)
If you got this far, you're awesome!