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?
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!