This blog has moved to a new location! http://iqandreas.github.com/

Tuesday, October 19, 2010

Understanding the AS3 Event System #3 - Easy Event Bubbling

This post can be found on the new blog at Understanding the AS3 Event System #3 - Easy Event Bubbling
This thread is part 3 in a "Understanding the AS3 Event System" series. It continues on the "office" illustration used in parts #1 and #2. If you have not read part 1, it is recommended that you do so:
http://iqandreas.blogspot.com/2010/10/understanding-as3-event-system-1-basics.html

This part describes how "Event Bubbling" works. Note that this is a strong simplification of the actual system (which is a bit more complex, but in the next part I will elaborate on that system), but for 99% of all Event uses, this is the only thing you really need to know about Event Bubbling.



At the office I work, a large part of our work system is set up as a hierarchy of responsibility and work delegation.

The Corporate Ladder
At the very top of the tree is Mr. Stan Stage. He's a great guy. Very friendly, a nice father figure, and a really good boss. He is the boss of all bosses, and in the end, everyone reports to him.

Since there is so much information passed around the office each day, he delegates a lot of the tasks to a handful of people who work right under him. These people are all "second in command". One of these second in command is my boss. Unlike Mr. Stage, my boss is very annoying and difficult, and to avoid his wrath, I will exclude his name, and instead just call him "My Boss".

My Boss has about 20 people working under him, including me. It's not a great position to be in, but it's still a very rewarding job. Some of us "third in command" workers have people working directly under us.

I am one of the lucky ones, and have five interns working directly for me. Since I am their boss, they obey my every whim, such as getting coffee for me each morning, or taking out my dry-cleaning. Even though they are only interns, they are still considered to be "fourth in command".


Since a great deal of what we do at the Office is reported via Events, my interns are expected to use the event system to report any changes just like the rest of us.

For efficiency's sake, my five interns have their desks very close to my cubicle, so whenever they dispatch an event (by standing up and shouting for example "I was hovered!") I hear it immediately.

Now, there are two types of Events. Events that Bubble, and Events that do not Bubble.


Non-Bubbling Events
Some Events are only important to the person which it actually happened to. For instance, one day one of my interns, Chris, stands up and yells "Hey everyone, I got a new car!"
dispatchEvent(new Event("new_car"));

A few of my other interns reacted. However, I honestly did not care. My Boss sure as hell doesn't care. And as nice of guy Steve Stage is, he really doesn't care either.

I'm not saying that Chris's Event wasn't important, in fact, it was quite important since it allows him to do his job better and will definitely affect his work. However, there is no need to tell as many people about it as possible. The only people who need to know about the event are people who specifically asked Chris to let them know whenever he got a new car.
chris.addEventListener("new_car", talkToChrisAboutTheCar);

Those Events do not Bubble up the corporate ladder.


Events that Bubble
Now, clicks are VERY important in my line of work (in fact, that's how we get paid).

We want to let as many people as possible who want to know about the clicks to know about the clicks, but if every single person just stood up and yelled "Someone was clicked!" whenever they found out about it, it would be one disorganized mess and you would hear about the same gossip from 8 different people. Instead, we have an organized system for letting everyone  in charge know about it.


Bubbling Events up the Ladder
One day Chris stands up and yells out to everyone "I was clicked!" (dispatching the event to everyone that may be listening to him. Not many people are usually listening to Chris (in fact, most people at the office don't even know any of my interns). So, Chris tells everyone listening to him about the click event.

Then Chris walks over to me and says "Andreas. I was clicked. All the information on the click is available in this file folder."

Now it's my turn. I stand up and yell "I was clicked!" (I could tell them "someone in my department was clicked", but since my interns work for me so closely, their work is considered to be part of my work) A few people are listening to me for the "clicked" event, (including Nico and Bob) and walk up to me asking for more information. I give them both the file so they have all the information on the event that they need.

Then, I barge into the office of my Boss, telling him all about the event, and handing him a copy of the information. He in turn switches on his fancy intercom system (since he is second in command, he gets certain perks, and is paid too much to have to yell across the hallway) and announces to everyone in the office "Attention anyone who is listening to me. I was just clicked." A few people are listening to him, and respond.

Finally, my Boss knocks on the door of Steve Stage and tells him all about the click event. Now, at last, Mr. Stage announces the click event for the last time, telling everyone who is listening to him about the click.

After that it is done. Everyone who needs to know about the event knows about it.


Now why is Bubbling so important?
Let's take the example of Betty, who works in accounting. In order to do her job property, she needs to know about every single time a client "clicked" an employee.

She could listen to every single employee for the "click" event, but this is a VERY inefficient system. And every time there is a new employee she would need to start listening to them, and when an employee leaves, she needs to remember to stop listening to them.

Instead, because of our nifty little bubbling system, Betty ONLY needs to listen Stage for the "click" event. Since those events bubble up to Steve, she will be notified of every single click event directly from Steve Stage.


EXTRA NOTE: Events only bubble upwards
Let's say one day I'm working at my desk, when a client clicks me directly instead of clicking one of my interns. I stand up and yell to everyone who is listening to me that "I was clicked", but I do not need to directly tell any of my interns about the click. Unless my interns are specifically listening to me, they will not know about the click and will keep carrying on their work undisturbed. The interns will NOT dispatch any "click" event either.

The only one who needs to know is My Boss. The events only bubble "up" the corporate ladder, not down.


So who was clicked first?
In order to file the proper paperwork (and hand out promotions or raises where needed) Betty needs to know exactly which person it was who was "clicked" first. Luckily, all this information is perfectly filled out in the Event object (the folder containing all the information).

There are two names in the Event object, "target" and "currentTarget". Flash assigns these two names automatically when the Event is dispatched.

These two properties tend to cause a lot of confusion among beginners. Sometimes they refer to the same person, sometimes they do not. To explain the difference, let's take another example.


Nico is listening to me for the "clicked" event.
andreas.addEventListener("clicked", onClick);

Chris, my intern, is clicked, and stands up and tells everyone about it. Nico doesn't even know Chris and therefore doesn't even know about the event. Chris tells me about the event and hands me all the information.

Now, I stand up and tell everyone "I was clicked". Nico is listening for the event, and walks over to me to gather all the information.

Then the event continues to bubble upwards to My Boss and finally Stan Stage.


target refers to the person who first dispatched the event. In this case, Chris would be the target.
currentTarget refers to the person you were listening to who told you about the event.

Think about "currentTarget" for a second. For Nico, currentTarget would refer to me, Andreas. However, since Betty is listening to Stan Stage for the Event, the currentTarget property in her event file would refer to Mr. Stage.


Using currentTarget to your advantage
Why does the "currentTarget" property even exist? I mean if you added the event listener to an object, of course you know what that object is, and therefore the property is pretty much worthless.

However, if used properly, it can save you a lot of code! For instance, perhaps you have several buttons on the stage "homeButton", "aboutButton", "contactButton", "newsButton", etc. You want the button to scale up when it is clicked. You could add the event listeners like this:

homeButton.addEventListener(MouseEvent.CLICK, homeButtonClicked);
aboutButton.addEventListener(MouseEvent.CLICK, aboutButtonClicked);
contactButton.addEventListener(MouseEvent.CLICK, contactButtonClicked);
newsButton.addEventListener(MouseEvent.CLICK, newsButtonClicked);

function homeButtonClicked(mev:MouseEvent):void
{
   homeButton.scaleX = 1.2;
   homeButton.scaleY = 1.2;
}
//etc...


That means, creating a different handler function for each button, which works, but creates a lot of extra code. Then if you want to change details of what happens when a button is clicked, you would need to update every single function.


Instead, you can create one single function which handles the clicks of all buttons. You can calculate which button needs to be pressed by using the "currentTarget" property.

homeButton.addEventListener(MouseEvent.CLICK, navigationButtonClicked);
aboutButton.addEventListener(MouseEvent.CLICK, navigationButtonClicked);
contactButton.addEventListener(MouseEvent.CLICK, navigationButtonClicked);
newsButton.addEventListener(MouseEvent.CLICK, navigationButtonClicked);

function navigationButtonClicked(mev:MouseEvent):void
{
   var pressedButton:DisplayObject = mev.currentTarget as DisplayObject;
   pressedButton.scaleX = 1.2;
   pressedButton.scaleY = 1.2;
}


Which uses only a single function! Now, if you need to change the scaling to 1.3, you only have to update it in one single place!


If you want to attach additional properties to the buttons, (such as setting some custom scale value for each button) you can use the Dictionary object. Look in the FAQ under the appropriate category for links to explanations and example code:
http://iqandreas.blogspot.com/2009/09/most-common-flash-questions-as3-faq.html



This is how Flash bubbles it's events. Next step, how to make your own events bubble.

Tuesday, October 12, 2010

Understanding the AS3 Event System #2 - Custom Events

This post can be found on the new blog at Understanding the AS3 Event System #2 - Custom Events
This thread is part 2 in a "Understanding the AS3 Event System" series. It continues on the "office" illustration used in part 1. If you have not read part 1, it is recommended that you do so:
http://iqandreas.blogspot.com/2010/10/understanding-as3-event-system-1-basics.html


I originally wrote this thread as a response to a Kirupa forum thread:
http://www.kirupa.com/forum/showthread.php?t=355040


This is my first draft, so any opinions or thoughts are deeply appreciated, especially if there is anything you still don't fully understand or would like me to clarify further.



Listen, don't tell my boss, but those days when work gets slow, I fire up some StarCraft! StarCraft is no fun alone, so Nico, Bob, Larry, and I all play against eachother. The problem is that we all need to be logged on at the same time in order to play together. I'm the one who plays the most, so I am the "Game Master" - the one who starts up the server, chooses a map, and waits for everyone else to join in.

We need some way to alert eachother when I start up a StarCraft game, AND keep it a secret from my boss (he reads all our emails, so I can't tell them via email). So, we use the Event system!


Custom Event Strings
We have planned that whenever I am about to start up a new game, I stand up and yell out to everyone "I am about to call Yamato!" (who our boss assumes is one of my Japanese clients)

Everyone knows that the custom event string (or event type) for when everyone listening should play starcraft is "Yamato". So, ahead of time, Nico, Bob, and Larry listen for my "Yamato" event:

Code:
homeButton.addEventListener("Yamato", startPlayingStarScraft);
Now, we may start playing dozens of different games, and I have chosen a different "code name" as the event string for each type of game:
Code:
homeButton.addEventListener("MarcoPolo", startPlayingAOE);
homeButton.addEventListener("Gelinor", startPlayingRuneScape);
homeButton.addEventListener("Germany", startPlayingCOD);
homeButton.addEventListener("Orcish", startPlayingWOW);

Custom Events
Now, I could create a different type of Event Folder for each type of game, such as StarCraftEvent, RuneScapeEvent, AOEEvent etc.

Each type of event file would have information inside of it, for instance, the "StarCraftEvent Folder" may have the following properties:
> the target - Me, since I'm the one "dispatching" the event
> the type - the custom event string, in this case "Yamato"
> map - the StarCraft map we will be playing in
> players - a list of all players
> settings - the game settings

And our class would look something like this (note that "target" and "type" are automatically inherited by the Event since you "extend" it)
Code:
public class StarCraftEvent extends Event
{
    public function StarCraftEvent(the_type:String, the_map:SCMap, the_players:Array, the_settings:GameSettings)
    {
        //Since you extend the Event, let the super class know a few more additional details
        super(the_type);
        
        map = the_map;
        players = the_players;
        settings = the_settings;
    }
    
    public var map:SCMap;
    public var players:Array;
    public var settings:GameSettings
}
This would be my totally custom made event class! Perfectly customized for whenever we want to start a StarCraft game, allowing everyone to get the information they need!


Dispatching the Custom Event
This is exactly as simple as it was dispatching the "clicked" event:
Code:
//Create the event
var players:Array = [Andreas, Nico, Bob, Larry];
var scEvent:StarCraftEvent = new StarCraftEvent("Yamato", lostTemple, players, defaultSettings);

//Dispatch the event (and it's folder containing all the info)
dispatchEvent(scEvent);
That dispatches an event which alerts everyone who is listening that I am about to start up a StarCraft game.

So, Nico, Bob, and Larry run up to my cubicle and I hand them all the StarCraftEvent Folder containing ALL the information they need to join in the game.


Do you really need to create Custom Events?
Now I can create a new Custom Event for each and every game we play and that would alright.

But I noticed, no one really reads the information in the Event Folder! I spent good money putting together and printing out all the information for those folders, and no one reads them! They get the file from me, then they run back to their own cubicles, fire up the game, and throw the Event Folder directly into the trash.

When you think about it, do they really NEED all that extra information such as maps or players? They will find all that information out anyway when they start up StarCraft. There really is no use going into all the hassle of creating custom events!

Instead, what if I print out a plain old Event Folder? All it says is the "target" and the "type", but if they want more information (which one one does) they can ask me for it directly.

FORGET about the hassle with the StarCraftEvent class, and just do this:
Code:
var eventFolder:Event = new Event("Yamato");
dispatchEvent(eventFolder);
99% of the time. That is all you will ever need. You save a lot of unnecessary work.


You don't always need to create custom Events, usually it is enough just using custom Event Strings.


That is Custom Events 101


Monday, October 11, 2010

Understanding the AS3 Event System #1 - The Basics

This post can be found on the new blog at Understanding the AS3 Event System #1 - the Basics
I originally wrote this thread as a response to a Kirupa forum thread:
http://www.kirupa.com/forum/showthread.php?t=355040

This is my first draft, so any opinions or thoughts are deeply appreciated, especially if there is anything you still don't fully understand or would like me to clarify further.


Imagine your code as one big office room. That office has about 100 or so cubicles, with each cubicle representing a different object. For instance, if you have 5 Buttons on the stage, it's not one "Button" cubicle, but instead 5 different cubicles, one for each button instance.


The Event String/Event Type
Now, I'm sitting in the "homeButton" cubicle. One day, I get an email from my boss who tells me I have been "clicked". So immediately I stand up, and yell out into the hallway so loudly that everyone can hear "I HAVE BEEN CLICKED!"

Now, the boss may have A LOT more information, such as where I was clicked, how many times, if any of my children were clicked, and a lot more information. However, I won't stand up and yell out to everyone in the building all that information. That is quite wasteful, and if I got several of those emails a day, I would soon get tired of spouting out all that information.

Instead, to save energy, I only tell everyone "I have been clicked". That is me telling everybody the event type, also known as the event string.


Listening for Events
Back up a few hours (before the event string). I have a friend named Nico sitting in the art department (his cubicle is labeled "currentImage" though that's not really that relevant). His boss told him "Whenever Andreas in the homeButton cubicle is clicked I want you to draw an image of a house and send it right to me."

Now, Nico could get up out of his seat every five minutes, walk over to me, and ask "Hey, Andreas. Were you clicked yet?" I say no, so he walks back to his cubicle and sits down. This would happen again and again, and neither of us would get any work done. This is VERY inefficient. Nico could reduce this and only check with me once per hour, but he wants to know immediately when I am clicked. So that is NOT an option either.

Instead, Nico sits in his cubicle continuing his regular work, and in the meantime, listens out in the hallway for my voice. Now, at around noon I yell out "I was keypressed!" He hears my voice, but he really doesn't care about the keypresses. So, he ignores what I say, and continues working. Then another guy in the cubicle (Larry, a really annoying guy) yells out "I was clicked!" Since Larry is not as good looking as Andreas, and The Boss didn't tell Nico to listen to Larry, Nico ignores him completely.

Because, Nico is only listening to Andreas (in the homeButton cubicle) for the "clicked" event. When he hears the event, he needs to start drawing the house (which looks something like this in AS3):

Code:
homeButton.addEventListener("clicked", drawHouse);
The Event is dispatched
Now, fast forward back to where we were. Me (Andreas) gets the call from my boss telling me I was clicked. So I stand up and yell out to everyone. "I was clicked!"

Two people were listening for my "clicked", Nico and Bob (the guy from 'contentManagement', a very talkative fellow) Nico rushes up to me excited "Hey Andreas. I heard about the click. That is awesome! Congratulations! But tell me more about the event! Why were you clicked? Where were you clicked? Who clicked you? Why did they click you?"

I could spend the next 5 minutes explaining all the juicy details to Nico, but then I would have to repeat all this information to Bob (which is very inefficient, and Bob is a busy man and doesn't want to wait). So instead, I print out all the information on the "clicked event" and put it into a Folder which I give to Nico. I give the folder to both Nico and Bob so they can use the information in it and look at it as they please. This folder is the Event object (more details on that later)

Immediatly Nico rushes to his art studio in his cubicle and gets to work at "drawHouse()", however, now he has the Folder (the Event) he can use that information while drawing the house, and therefore passes it into the function as a parameter:
Code:
function drawHouse(event:Event)
{ /*Draw stuff in here...*/ }
The Event
To make sure that everyone gets the information they need, there are VERY strict protocols to what the Event Folder needs to contain.

The following pages with information are required for standard Event Folders
>the target - the person dispatching the event, which in this case is me, Andreas (or actually the homeButton cubicle).
>event type - the type of event (aka event string), in this case "clicked".
(there are a few more pages in the file, but that's mostly the small legal mumbo-jumbo fine print that no one reads anyway. You will be fine ignoring them for now.)

This is a standard Event file. But hold on, there was A LOT more information which is missing here! If I hand Nico a file with only those two pages of information in it, he will still wonder "Where were you clicked?" among MANY other important questions. Luckily, the company already has a neat system figured out!


The MouseEvent
Now, the company I work for has a second type of file, a "MouseEvent File". This file extends the standard Event File. That means that the MouseEvent file has all the information contained in the plus a lot more information, perfect for when a "clicked" event happened.

It has the standard two fields (target and type) PLUS these additional pages with information:
>localX
>localY
>stageX
>stageY
>altKey
>ctrlKey
And a whole lot more!

Note that this MouseEvent file ONLY is allowed to be used when dealing with events that had to do with the mouse, such as "clicked", "hovered" etc. The file should NOT be used for events that had to do with the keyboard, "keypressed" or "keyreleased". Those events should instead use a specialized KeyboardEvent File with it's own special properties.


So I print out all the relevant information and hand both Nico and Bob a "MouseEvent" folder. Using that information, they draw the houses, or display text, or whatever they want to do with the information.

(Extra note: Maybe Bob didn't even need to see the file. Maybe he just needed to know that I was clicked, so when I hand him the file, he may not even open it or look at the details of the click using the information inside. That's fine by me, but I still need to create the file in case there is someone out there who actually needs the information.)


Creating the MouseEvent
Bob and Nico don't want to wait for me to print out and collect all the papers needed in the MouseEvent file. They want the information to be ready the second they step up to my cubicle. So, BEFORE I stand up and tell everyone I was clicked, I create the folder ahead of time for quick and easy access. THEN, I dispatch it to all who are listening.

This is how it looks in ActionScript:
Code:
//create the folder with all the information in it
var eventFolder:MouseEvent = new MouseEvent("clicked", bla, bla, localX, localY, bla, bla, bla, bla, more bla);

//Now stand up and tell everyone I was clicked
//The "eventFolder" already says the event type is "clicked",
// so I don't need to repeat myself when dispatching it.
//All I need to do is dispatch the folder and Flash will do all the dirty work
dispatchEvent(eventFolder);
Now Nico and Bob (and whoever else is listening) can react to it and get to see the folder I sent when dispatching:
Code:
function drawHouse( andreasEventFolder:MouseEvent )
{ /*Draw stuff in here...*/ }
That is Events 101.