MGAS3FD 6: Click it like it's hot


Hello there. This is the sixth part of the Making Games in ActionScript 3 using FlashDevelop

By now we’ve got almost all the basic building blocks to make a simple game. All that is missing is how to get some input. Last time we touched on it a little bit using the mouseX and mouseY properties.
Those are the most straightforward to get at, but other inputs aren’t very complicated either. Let’s start with the mouse button.


Note that it’s mouse button, not buttons, one of the limitations of the Flash platform is that you only have access the to the left click.
Right click gives a menu, and there’s no getting around that.

To get the most of out of this part we need to start with making a Player class. Check back in part three for how to add a class but name it Player this time. Add an instance of the player to your Main class and make sure it’s on the stage. If you’re too lazy just get the prepared project here.

Getting input brings us back to the event handling we started with in last part, in your Enemy class’ constructor add an event listener for MouseEvent.CLICK:

addEventListener(MouseEvent.CLICK, handleClick);

Once this is done we add the handler method, use the neat CTRL+1 autocompletion or just type this out (copypaste is cheating).

private function handleClick(e:MouseEvent):void {
	trace("clicked enemy");
}

Give the Enemy a click, and gasp at the fantasticness of the traced output. You will notice that if you click outside the enemy nothing is traced. This is because we are listening for clicks on that specific object. If you add multiple enemies they will each have their own handler for clicks.

Sometimes this is great, other times, not so great. What if you have a whole bunch of enemies and want to do something in your main class when any one of them is clicked. You can use this exact method and let the enemy call a function on your Main class, but that’s not very pretty code.
Adding a listener to each one from the Main class is a possibility, since a handler can handle events from many “dispatchers” (things that broadcast events are called dispatchers). But, we don’t want to repeat ourselves unless we absolutely have to.

So, we’re going to do it the neat way. Add another listener, this time in the Main class. Do it the exact same way, but let’s put a different trace in so we can tell them apart:

private function handleClick(e:MouseEvent):void {
	trace("clicked in main");
}

For this example to work we’ll need a couple of extra enemies. Since we don’t really need a reference to them we can do it like this:

for (var i:int = 0; i < 5; i++) {
	var tmpEnemy:Enemy = new Enemy();
	tmpEnemy.x = Math.random() * 800;
	tmpEnemy.y = Math.random() * 600;
	addChild(tmpEnemy);
}

What we do here is first a small loop, this is a classic for loop, if you need to read up on what the arguments are a quick googling should help you out. Then we create a temporary variable to hold a reference to the enemy we’re about to create. We use that to position the enemy at a random spot on the stage. Math.random() returns a random number between zero and one, we multiply that with the stage size we’ve set in the project properties (800×600 is the default in FlashDevelop). The Math class contains all the math related methods, so we’ll see more of that in a later parts of these tutorials.

Run it and give any Enemy a good clickin’, you should see both the trace statements in your output. The attentive log reader notices that the enemy’s trace always arrives before the main trace. This is because of something called event bubbling.

This means that when a object added as a child to something receives a click (or any other event) this event will bubble up the hiearachy to it’s parent. The parent will in turn bubble it further and so on. Thus, by listening for click events on our Main class we’re getting all clicks in the whole application. Almost.

The click registration respects the objects shape (it doesn’t handle images with alpha though). A good way to visualise this is to set the enemys propety buttonMode to true. This will give you the hand cursor whenever you’re in a position that would click that object.

If you want to listen for all clicks you will need to add a listener to the stage. This will give you all clicks even those that aren’t really on anything, but we’re not going to need that right now.

Knowing what got clicked is real easy when you’re only listening for clicks on a specific object, but as you’ve seen that’s not always the case.

You have probably noticed that the event handling functions accept an argument. I (and Flash Develop) almost always name this e:

private function handleClick(e:MouseEvent):void

But you can name it however you want, it will have to be there however  since that’s where all the information about the event goes.

You can use FlashDevelops autocompletion to take a look what properties are available, there’s quite a lot of them. We’ll focus on the one named target for now.
The target is the object that initally dispatched the event. In our case that will be either one of the enemies or your new Player class, assuming this is the listener we set up in Main.

This property is an object which is one of the most basic datatypes in Flash. This is because the thing that dispatched the event could be of any type. To get at the actual Enemy we’ll need to cast it.

If all you care about is what class the target was you can do it like this:

if (e.target is Enemy) {
	trace("run away");
}

This is pretty straightforward, the is operator compares the target to a class and evaluates to true if it’s a match. But there are other neat tricks you can do which are especially useful if you want to do something with the target.

Try assigning your enemy to a variable in the handler:

var targetEnemy:Enemy = e.target;

The compiler will whine about this, since we’re trying to put a generic object into something that’s meant to hold an enemy. To get around this we need to specify that this infact is what we want to do:

var targetEnemy:Enemy = e.target as Enemy;

Now, if this succeeds the enemy will be accesible via the variable, if it fails the variable will be null. This combined with the fact that in actionscript everything can be evaluated as a Boolean lets us do like this:

var targetEnemy:Enemy = e.target as Enemy;

if(targetEnemy) {
	targetEnemy.y += 20;
}

If you click the player the cast will fail and targetEnemy will be null. null will evaluate as false, and a reference will be true so we can safely do stuff with our enemy inside. Neat, huh?

Posted in code, Making Games in Actionscript 3.0, Tutorials |

39 Responses to MGAS3FD 6: Click it like it's hot

  1. thank you for such a great tutorials! I’ve completed all of them now, got a question: I’ve made Player class to be “extends Bitmap”. The problem is that it doesn’t let to handle mouse click event. What is a common workaround for this?
    thanks again!

  • Glad you like them!
    I adress this exact problem in part 4, the trick is to have your player extend Sprite and add another child to that one with the actual graphics.

  • Thank you for answering! Yeah, I’ve got the trick from previous part, but do I correctly understand that I’ll need to make the Player (that extends Sprite) display nothing, while having a Bitmap child?

    One more question 🙂 Let’s say I want a little animated spark appear on my game object (a gem, for instance). I may guess that the easiest way will be to make it a vector animation in Flash CS4, save it as .swf and embed it into the game, like you embed leek.swf in Part 3. But is there another way to make it without using Flash? I mean maybe there are other programs that allow simple vector animation authoring with swf export?

    Also, here are a few ideas on possible new tutorials (feel free to ignore them 🙂 :
    1)Organizing main game loop

    2)Display list objects (and tweening using external libs) VS blitting sprites

    3)Creating simple UI

    Once again – thank you for great tutorials!

    • Yeah, having the Player class “empty” is exactly what I suggest, that’s the most flexible way IMO.
      I stick to the Flash Authoring tool (what you call Flash CS4) to do my vector graphics, but nowadays the full specs for swf are publically available, so there should be other tools that can export to that format aswell. Although I don’t have any good suggestions.
      A Sprite blitting tutorial is not anything that’s going to be covered here anytime soon, it is possible in Flash, but it does go against much of the good parts of the tech and is in my opinion a step back. It is however useful for some effects, but I wholeheartedly recommend sticking with the regular Displaylist.
      But the other two will most certainly be touched upon in upcoming parts.

  • Thank you! Looking forward to next parts!

  • hrm…

    I tried typing it in and copypaste and:

    for (var i:int = 0; i < 5; i++) {

    Output asks for a right parenthesis before the semicolon after the 5 and a semicolon to the right of the i++ but when I add those things it throws more errors.

    I wonder if I am just attempting to put this in the wrong place. Where exactly does the loop go? I have tried it in a variety of places and still run into the same errors.

  • it seems i have some html escaping issues with the code-blocks, the & lt; is supposed to be a “less than” sign <

    i'll look into fixing this asap!

  • Any luck with fixing the & lt; ? I just added your Making Games in ActionScript 3.0 series as the first tutorial that people should try if they want to learn AS3 game programming, but I know mistakes like this could really confuse beginners who don’t know any better! (click my name to see the article I wrote)

    Otherwise, I really like the clarity and thoroughness of your tutorials. If you find the time to make any more, I will be eager to read them. 🙂

  • Great tutorial, thanks for sharing!

  • awesome tutorials 🙂 learned quite a bit from it 🙂

  • Aaaaaaahhhhhhhhhh hurr.

    I spent two hours trying to work out an apparently nonsensical “Access of undefined property x in package player” error message. I finally randomly guessed the problem: I had saved the Player class in a folder called “Player”, instead of in the root folder. All the code referred to the Player folder correctly, but the word must be reserved for something else in Actionscript, because when I renamed the folder it worked perfectly.

    Ok, now that I’ve proved my credentials as a total n00b, I’ll give you a little feedback on what it’s like for a novice to read these tutorials. The information is great, it’s broken down well step-by-step, and it’s explained clearly for the most part, but towards the middle you stop explaining where to put things: a lot of passages say “now add this code” without any hint as to where to write it. I muddled through mostly by trial and error.

    But I got there in the end! It feels like a victory, but it’s daunting to think how much there is still to learn. 😡

    Thanks for taking the time to write out this very helpful tutorial. You’ve earned good internet karma!

  • Huh. That should be a “troubled” emoticon, not an angry one.

  • I’m using the most update version of FlashDevelop (3.0.6) and when I try using “e.target” the compiler comes back with tears in it’s eyes and proceeds to tell me “Error: Access of undefined property e”. Can anyone explain to me why the e.anything expression won’t work?

    Thanks 😮

  • @LopTank – Did you put the e:GumMixEvent in the arguments for the eventhandler? (See the second code block in the post)

  • When I put the trace for “Clicked in the main” It only shows up when I click on the gnome along with the other trace. And nothing shows up when I just click the background. I put everything where u said, maybe I should check the source files real quick 😛

  • Nevermind I figured it out, the click in the main detects it for all the enemies. It’s a bit unclear there.

  • These are great, two thumbs up!

  • My ship sails in the morning.
    I wonder when the next part will be posted…

  • Hey! Very helpful tutorials. Thanks for helping guys like me get started in ActionScript 3.

  • Hello grapefrukt,
    I really like your tutorials, however I have a problem. I have added the Click eventlistener to my Enemy class which extends Sprite, yet the event doesn’t occur when I try to do it runtime.

    What could be the problem?

  • I really like this tutorial series. Should be required reading for anyone trying to get up to speed on Action Script 3 with Flash Develop. I see the last installment was posted a year ago :(. Sure hope it picks up again, it’s very helpful!

  • Hi grapefrukt,

    Thanks for the tutorial! I am having a little trouble with adding another listener in the main class. I get an error Duplicate function definition. Could you post the final code?

  • Thanks for the tutorial! I’m having the opposite problem as above, my document class handleClick function does not seem to get called at all. I don’t get any errors it just seems like the bubbling is not working/turned on?

  • I’m really new to programming in general and I’m having trouble figuring out where to put this:

    private function handleClick(e:MouseEvent):void {
    trace(“clicked in main”);
    }

    and the loop:

    for (var i:int = 0; i < 5; i++) {
    var tmpEnemy:Enemy = new Enemy();
    tmpEnemy.x = Math.random() * 800;
    tmpEnemy.y = Math.random() * 600;
    addChild(tmpEnemy);
    }

  • It’s kind of awkward the way you tell us to make a player class and then don’t touch in the subject anymore.

    Leonardo "Brazil Rules", November 12, 2010 at 23:41
  • Can someone please post the final working code for this?

    I am having issues with Error: Access of undefined property e.

  • Thanks for the tutorials, they’ve been a real help.

    I didn’t really understand the piece on e:target, I think you wanted me to make another eventlistener of some kind but I couldn’t find target in any of the drop down options when I used Event or MouseEvent. Maybe it requires a different event to be used to access it?

    Also, I’m not sure why we made a player class, it just seems to be there to act as another trace statement.

    Either way, I’m sure I’ll figure it out the e:target thing on my own, thanks for providing the initial steps into programming for me.

  • Really interesting. I’m looking into returning to content creation after a 10 year break so pretty much back at the beginning – 1st tutorial I’ve found that made any real sense 🙂
    I really enjoyed reading – I hope you find the time and impetus to continue with these at some point!

  • For those still struggling with the e.target function. Took me a while to figure it out, but turns out to be a relatively simple omission: just put it inside the handler in the Main class (eg. the one where he asks you to trace click in main). I guess this is because the handler defines what e is at its start, so there!

    Thanks again for the tutorials -lol definitely doesn’t hold your hand but definitely very informative, ta!

  • Nice tutorial, tnx for all.

  • I’m having the exact same problem as Jeff :/ new to this though I have had quite a bit of experience in C/C++. any ideas? thnx 🙂

  • @Mac, you probably did the same thing I did and forgot to add:

    addEventListener(MouseEvent.CLICK, handleClick);

    In your Main() section. That is what tells the Main() function to pay attention to mouse clicks and call handleClick() whenever it notices one.

  • Stopped working in part 4. Even the downloaded code does not work & no downloads in the final parts. “Error: Unable to transcode ../../../../../../assets/gardengnome.png”. Spent a lot of time working out where to put code & why & the difference between static & const. A bit half-hearted, but would be a good tutorial if complete. Thanks a bit !

  • Correction: Just found the download at the top of part 6. It displays the graphics, but nothing moves. Don’t know why it threw an error before as I can’t see any difference in the code or folder structure.

  • These are really great tutorials, but it gets kind of hard near the end, but I eventually figured it out. If anyone comes by here and needs some help, here is my final code.

    package
    {
    import enemies.Enemy;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;

    public class Main extends Sprite
    {
    public var enemy:Enemy;
    public var player:Player;

    public function Main():void
    {
    addEventListener(Event.ENTER_FRAME, handleEnterFrame);
    addEventListener(MouseEvent.CLICK, handleClick);

    player = new Player();
    addChild(player)

    enemy = new Enemy();
    addChild(enemy)
    enemy.x = 500;
    enemy.y = 400;

    for (var i:int = 0; i < 5; i++)
    {
    var tmpEnemy:Enemy = new Enemy();
    tmpEnemy.x = Math.random() * 800;
    tmpEnemy.y = Math.random() * 600;
    addChild(tmpEnemy);
    }

    }

    private function handleEnterFrame(e:Event):void
    {
    player.x += 1;
    player.x = mouseX;
    player.y = mouseY;
    }

    private function handleClick(e:MouseEvent):void
    {
    trace("clicked in main");
    var targetEnemy:Enemy = e.target as Enemy;

    if (targetEnemy)
    {
    targetEnemy.y += 20;
    }

    }

    }

    }

    Hope this helps!!!

  • AddEventListener dosnt seem to work in any class except main. it compiles and runs, but dosnt catch and clicks on its assiged object.

    help??

  • MORE MORE MORE PLEASE I WANT TO COMPLETE GAME

  • 4 years and no more parts… Are you dead?

  • Hi Everyone,

    I also wonder what happened to our AS3 “teacher”. I really enjoyed his/her teaching. I hope he/she will return one day and continue the teaching. I would like to learn how you handle sprite collisions, scoring, removing objects when hit by other objects, scrolling of backgrounds, taking/porting the game to IOS and Android etc, etc.

    A tip for those of you that follows the tutorial to the teeth but got no response when clicking the “enemy” object, remember to look in your toolbar at the top of your development tool for the dropdown saying “Release”. It should be next to the blue triangle. That dropdown value should be “Debug”. You will only see the “trace” messages displaying in your “Output” window when that setting is “Debug” just before you “Build” or “Test/Run” your project.

    When you sometimes download the project files and overwrites your project with his/her project files you will find that setting is set to “Release” and you need to set it back to “Debug”.

    Happy Flashing.

    Gert Myburgh
    South Africa

  • Comments are closed.