logo
468x60-2-495


  • Home
  • Privacy Policy
  • About
search
top
Jan 23, 2012 Posted on Jan 23, 2012 in Hints and Tips | 10 comments

Easy, Fluid Keyboard Movement in AS3 With the Input Class

There are a lot of games out there with jerky, unrealistic movements and that can do only one thing to your product: make it unappealing to the audience. But smooth movement is not hard to achieve – let’s get to work!


Final Result Preview

Let’s take a look at the final result we will be working towards:


Step 1: Set Up the Environment

This is a straight forward tutorial, so the setting up will also be straight forward.

Create a New ActionScript 3.0 Flash Project. The stage size and color don’t matter, just use what you are confortable with.

I use FlashDevelop for coding, but also this could be done in any AS editor, like Flash Pro (or any text editor, maybe Notepad ;) ). So, create a Class file, make sure your code looks pretty much like mine; see below. I called mine “Movement”. (If you’re using Flash Pro, check out this guide to creating a class.)

package {
	import flash.display.Sprite;

	public class Movement extends Sprite {

		public function Movement():void {

		}
	}

}

After you’re done, make sure your Class is linked to the Flash project as the Main Class.


Step 2: Create the Square and Variables

So after you’ve linked the Movement Class to your document, define the variables as I did below

package {
	import flash.display.Sprite;
	import flash.events.Event;

	public class Movement extends Sprite {

		//The object that will move
		private var square:Sprite;

		//The maximum speed
		private var _max:Number = 10;

		//The variables that are going to be applied to move the square
		private var dx:Number = 0;
		private var dy:Number = 0;

		public function Movement():void {
			//Listen for added to stage event
			addEventListener(Event.ADDED_TO_STAGE, init);
		}

		private function init(e:Event):void {
			removeEventListener(Event.ADDED_TO_STAGE, init);

			//Creating a new Sprite and draw inside a square
			square = new Sprite();
			square.graphics.beginFill(0x333333);
			square.graphics.drawRect(0, 0, 30, 30);
			square.x = stage.stageWidth / 2 - square.width / 2;
			square.y = stage.stageHeight / 2 - square.height / 2;
			addChild(square);
		}
	}

}

This is pretty much all that we’ll do for creating the object. You can use your own object but for this simple movement tutorial I used this simple square.


Step 3: Introducing the Input.as Class

Hi guys, this is the Input.as Class; Input.as Class these are the guys I told you about – be nice to them! :)

So what is this class about, you may wonder. Basically it does your key handling job for you. It adds a listener to ENTER_FRAME events – with low priority – and a key listener which fills some private Dictionaries. Also it uses another Class for key codes. You can take a look inside and see for yourself how is working.

Note: The Input.as Class does not belong to me. It was created by Matthew Bush, who ported Box2D to Flash.

//Example of Input.as Class usage

//You have to always initialize it as this with the stage parameter
Input.initialize(stage);

//After initializing, you can use kd(), kp() or ku() methods, which
//return a Boolean value if the conditions are met.
//These methods accept multiple arguments,
//so for one event you can use multiple keys.
//This makes it a lot easier to give a boost of accessibility to your app.
//e.g See below as I use one call for detecting UP arrow or W for going up.
Input.kd("UP", "W");

Step 4: Importing the Classes

So now that you are familiar with the Input.as Class, we are going to import it in our Movement Class and initialize it.

package {
	import flash.display.Sprite;
	import flash.events.Event;
	import Input;

	public class Movement extends Sprite {

		//The object that will move
		private var square:Sprite;

		//The maximum speed
		private var _max:Number = 10;

		//The variables that are going to be applied to move the square
		private var dx:Number = 0;
		private var dy:Number = 0;

		public function Movement():void {
			//Listen for added to stage event
			addEventListener(Event.ADDED_TO_STAGE, init);
		}

		private function init(e:Event):void {
			removeEventListener(Event.ADDED_TO_STAGE, init);

			//Creating a new Sprite and draw inside a square
			square = new Sprite();
			square.graphics.beginFill(0x333333);
			square.graphics.drawRect(0, 0, 30, 30);
			square.x = stage.stageWidth / 2 - square.width / 2;
			square.y = stage.stageHeight / 2 - square.height / 2;
			addChild(square);

			//Initialize the Input.as Class with handler on stage
			Input.initialize(stage);

			//Add the refresh loop
			addEventListener(Event.ENTER_FRAME, refresh);
		}

		private function refresh(e:Event):void {

		}
	}

}

Step 5: Handling the Key Inputs

I use an ENTER_FRAME-based loop for detecting the key inputs; below is the refresh() method which is the handler function for this event.

private function refresh(e:Event):void {
	//Key Handler
	if (Input.kd("A", "LEFT")) {
		//Move to the left
	}
	if (Input.kd("D", "RIGHT")) {
		//Move to the right
	}

	if (!Input.kd("A", "LEFT", "D", "RIGHT")) {
		//If there is no left/right pressed
	}

	if (Input.kd("W", "UP")) {
		//Move up
	}
	if (Input.kd("S", "DOWN")) {
		//Move down
	}

	if (!Input.kd("W", "UP", "S", "DOWN")) {
		//If there is no up/down action
	}
}

Step 6: Explaining the Calculations – Handling the Velocity

This is pretty straight forward. Detect whether any of the keys are pressed, then act accordingly.

I use the ternary operator a lot: value = condition ? true : false;
This is basically an if-statement that’s been condensed to a single line.

For every key detection, I use this method: if the value is bigger than _max then set it equal to _max; otherwise, increment or decrement that particular value as appropriate. This way, it’s kept within certain bounds. Simple, right?

Below you can study the conditions:

private function refresh(e:Event):void {
	//Key Handler
	if (Input.kd("A", "LEFT")) {
		//Move to the left
		dx = dx < 0.5 - _max ? _max * -1 : dx - 0.5;
	}
	if (Input.kd("D", "RIGHT")) {
		//Move to the right
		dx = dx > _max - 0.5 ? _max : dx + 0.5;
	}

	if (!Input.kd("A", "LEFT", "D", "RIGHT")) {
		//If there is no left/right pressed
		if (dx > 0.5) {
			dx = dx < 0.5 ? 0 : dx - 0.5;
		} else {
			dx = dx > -0.5 ? 0 : dx + 0.5;
		}
	}

	if (Input.kd("W", "UP")) {
		//Move up
		dy = dy < 0.5 - _max ? _max * -1 : dy - 0.5;
	}
	if (Input.kd("S", "DOWN")) {
		//Move down
		dy = dy > _max - 0.5 ? _max : dy + 0.5;
	}

	if (!Input.kd("W", "UP", "S", "DOWN")) {
		//If there is no up/down action
		if (dy > 0.5) {
			dy = dy < 0.5 ? 0 : dy - 0.5;
		} else {
			dy = dy > -0.5 ? 0 : dy + 0.5;
		}
	}

	//After all that, apply these to the object
	square.x += dx;
	square.y += dy;
}

If you’re unfamiliar with the ternary operator, grab a piece of paper and a pen and write out a few of them in if…else format; it’s a great exercise to get to grips with that’s going on.

Keep in mind I manipulate the dx and dy variables, and only set the actual x and y values at the end. This helps us make the motion fluid; it’s not jerking around as we alter their values directly throughout the function..

Go on, test it! See how nicely it’s moving?


Step 7: Handling Boundary Collisions

Okay. Everything is right, moving fluidly – but OUT of the stage! Below I added the collision detection conditions.

private function refresh(e:Event):void {
	//Key Handler
	if (Input.kd("A", "LEFT")) {
		//Move to the left
		dx = dx < 0.5 - _max ? _max * -1 : dx - 0.5;
	}
	if (Input.kd("D", "RIGHT")) {
		//Move to the right
		dx = dx > _max - 0.5 ? _max : dx + 0.5;
	}

	if (!Input.kd("A", "LEFT", "D", "RIGHT")) {
		//If there is no left/right pressed
		if (dx > 0.5) {
			dx = dx < 0.5 ? 0 : dx - 0.5;
		} else {
			dx = dx > -0.5 ? 0 : dx + 0.5;
		}
	}

	if (Input.kd("W", "UP")) {
		//Move up
		dy = dy < 0.5 - _max ? _max * -1 : dy - 0.5;
	}
	if (Input.kd("S", "DOWN")) {
		//Move down
		dy = dy > _max - 0.5 ? _max : dy + 0.5;
	}

	if (!Input.kd("W", "UP", "S", "DOWN")) {
		//If there is no up/down action
		if (dy > 0.5) {
			dy = dy < 0.5 ? 0 : dy - 0.5;
		} else {
			dy = dy > -0.5 ? 0 : dy + 0.5;
		}
	}

	//Boundary detection
	if (square.x - dx < 0 || square.x + dx + square.width > stage.stageWidth) {
		//x axis detection
	}

	if (square.y - dy < 0 || square.y + dy + square.height > stage.stageHeight) {
		//y axis detection
	}

	//After all that, apply these to the object
	square.x += dx;
	square.y += dy;
}

It’s looking for boundaries in a more precise fashion, by checking whether the edges of the square hit the boundaries (before this, it was just checking the center of the square against the boundaries).

Great. Now we need to add the code to make the square bounce off the boundaries. What I do for that is multiply by -1 the axis value dx or dy. But that is not enough! If the speed is quite fast, then the square will get through the margins or just go nuts. So before we multiply we need to set the x or y of the object to be the same as the boundary that it meets.

So if x < 0 (and so it is colliding with the left edge), then we move the object to be exactly on the left edge, like so: object.x = 0; and then multiply the dx by -1.

//Margin detection
if (square.x - dx < 0 || square.x + dx + square.width > stage.stageWidth) {
	//x axis detection
	square.x = square.x - dx < 0 ? 0 : stage.stageWidth - square.width;
	dx *= -1;
}

if (square.y - dy < 0 || square.y + dy + square.height > stage.stageHeight) {
	//y axis detection
	square.y = square.y - dy < 0 ? 0 : stage.stageHeight - square.height;
	dy *= -1;
}

Test it now! Bouncy right? :)

To make it even better, go on experimenting with different values - like instead of multiplying by -1, try -0.7 and see the results.


Conclusion

So you met the Input.as Class, got to know how to work with it, and made a nice fluid movement in just a few minutes. I think this counts as a great time!

Please leave your comments below and any other questions, I will gladly answer.

But if you encounter any problem please check twice your code, compare it with the source file and then if you can't make it work, feel free to post a question.



View full post on Activetuts+

banner ad

10 Responses to “Easy, Fluid Keyboard Movement in AS3 With the Input Class”

  1. Cristian Bote says:
    January 23, 2012 at 9:33 pm

    There are a lot of games out there with jerky, unrealistic movements and that can do only one thing to your product: make it unappealing to the audience. But smooth movement is not hard to achieve – let’s get to work!


    Final Result Preview

    Let’s take a look at the final result we will be working towards:


    Step 1: Set Up the Environment

    This is a straight forward tutorial, so the setting up will also be straight forward.

    Create a New ActionScript 3.0 Flash Project. The stage size and color don’t matter, just use what you are confortable with.

    I use FlashDevelop for coding, but also this could be done in any AS editor, like Flash Pro (or any text editor, maybe Notepad ;) ). So, create a Class file, make sure your code looks pretty much like mine; see below. I called mine “Movement”. (If you’re using Flash Pro, check out this guide to creating a class.)

    
    
    package {
    	import flash.display.Sprite;
    
    	public class Movement extends Sprite {
    
    		public function Movement():void {
    
    		}
    	}
    
    }
    

    After you’re done, make sure your Class is linked to the Flash project as the Main Class.


    Step 2: Create the Square and Variables

    So after you’ve linked the Movement Class to your document, define the variables as I did below

    
    
    package {
    	import flash.display.Sprite;
    	import flash.events.Event;
    
    	public class Movement extends Sprite {
    
    		//The object that will move
    		private var square:Sprite;
    
    		//The maximum speed
    		private var _max:Number = 10;
    
    		//The variables that are going to be applied to move the square
    		private var dx:Number = 0;
    		private var dy:Number = 0;
    
    		public function Movement():void {
    			//Listen for added to stage event
    			addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    
    		private function init(e:Event):void {
    			removeEventListener(Event.ADDED_TO_STAGE, init);
    
    			//Creating a new Sprite and draw inside a square
    			square = new Sprite();
    			square.graphics.beginFill(0x333333);
    			square.graphics.drawRect(0, 0, 30, 30);
    			square.x = stage.stageWidth / 2 - square.width / 2;
    			square.y = stage.stageHeight / 2 - square.height / 2;
    			addChild(square);
    		}
    	}
    
    }
    

    This is pretty much all that we’ll do for creating the object. You can use your own object but for this simple movement tutorial I used this simple square.


    Step 3: Introducing the Input.as Class

    Hi guys, this is the Input.as Class; Input.as Class these are the guys I told you about – be nice to them! :)

    So what is this class about, you may wonder. Basically it does your key handling job for you. It adds a listener to ENTER_FRAME events – with low priority – and a key listener which fills some private Dictionaries. Also it uses another Class for key codes. You can take a look inside and see for yourself how is working.

    Note: The Input.as Class does not belong to me. It was created by Matthew Bush, who ported Box2D to Flash.

    
    
    //Example of Input.as Class usage
    
    //You have to always initialize it as this with the stage parameter
    Input.initialize(stage);
    
    //After initializing, you can use kd(), kp() or ku() methods, which
    //return a Boolean value if the conditions are met.
    //These methods accept multiple arguments,
    //so for one event you can use multiple keys.
    //This makes it a lot easier to give a boost of accessibility to your app.
    //e.g See below as I use one call for detecting UP arrow or W for going up.
    Input.kd("UP", "W");
    

    Step 4: Importing the Classes

    So now that you are familiar with the Input.as Class, we are going to import it in our Movement Class and initialize it.

    
    
    package {
    	import flash.display.Sprite;
    	import flash.events.Event;
    	import Input;
    
    	public class Movement extends Sprite {
    
    		//The object that will move
    		private var square:Sprite;
    
    		//The maximum speed
    		private var _max:Number = 10;
    
    		//The variables that are going to be applied to move the square
    		private var dx:Number = 0;
    		private var dy:Number = 0;
    
    		public function Movement():void {
    			//Listen for added to stage event
    			addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    
    		private function init(e:Event):void {
    			removeEventListener(Event.ADDED_TO_STAGE, init);
    
    			//Creating a new Sprite and draw inside a square
    			square = new Sprite();
    			square.graphics.beginFill(0x333333);
    			square.graphics.drawRect(0, 0, 30, 30);
    			square.x = stage.stageWidth / 2 - square.width / 2;
    			square.y = stage.stageHeight / 2 - square.height / 2;
    			addChild(square);
    
    			//Initialize the Input.as Class with handler on stage
    			Input.initialize(stage);
    
    			//Add the refresh loop
    			addEventListener(Event.ENTER_FRAME, refresh);
    		}
    
    		private function refresh(e:Event):void {
    
    		}
    	}
    
    }
    

    Step 5: Handling the Key Inputs

    I use an ENTER_FRAME-based loop for detecting the key inputs; below is the refresh() method which is the handler function for this event.

    
    
    private function refresh(e:Event):void {
    	//Key Handler
    	if (Input.kd("A", "LEFT")) {
    		//Move to the left
    	}
    	if (Input.kd("D", "RIGHT")) {
    		//Move to the right
    	}
    
    	if (!Input.kd("A", "LEFT", "D", "RIGHT")) {
    		//If there is no left/right pressed
    	}
    
    	if (Input.kd("W", "UP")) {
    		//Move up
    	}
    	if (Input.kd("S", "DOWN")) {
    		//Move down
    	}
    
    	if (!Input.kd("W", "UP", "S", "DOWN")) {
    		//If there is no up/down action
    	}
    }
    

    Step 6: Explaining the Calculations – Handling the Velocity

    This is pretty straight forward. Detect whether any of the keys are pressed, then act accordingly.

    I use the ternary operator a lot: value = condition ? true : false;
    This is basically an if-statement that’s been condensed to a single line.

    For every key detection, I use this method: if the value is bigger than _max then set it equal to _max; otherwise, increment or decrement that particular value as appropriate. This way, it’s kept within certain bounds. Simple, right?

    Below you can study the conditions:

    
    
    private function refresh(e:Event):void {
    	//Key Handler
    	if (Input.kd("A", "LEFT")) {
    		//Move to the left
    		dx = dx < 0.5 - _max ? _max * -1 : dx - 0.5;
    	}
    	if (Input.kd("D", "RIGHT")) {
    		//Move to the right
    		dx = dx > _max - 0.5 ? _max : dx + 0.5;
    	}
    
    	if (!Input.kd("A", "LEFT", "D", "RIGHT")) {
    		//If there is no left/right pressed
    		if (dx > 0.5) {
    			dx = dx < 0.5 ? 0 : dx - 0.5;
    		} else {
    			dx = dx > -0.5 ? 0 : dx + 0.5;
    		}
    	}
    
    	if (Input.kd("W", "UP")) {
    		//Move up
    		dy = dy < 0.5 - _max ? _max * -1 : dy - 0.5;
    	}
    	if (Input.kd("S", "DOWN")) {
    		//Move down
    		dy = dy > _max - 0.5 ? _max : dy + 0.5;
    	}
    
    	if (!Input.kd("W", "UP", "S", "DOWN")) {
    		//If there is no up/down action
    		if (dy > 0.5) {
    			dy = dy < 0.5 ? 0 : dy - 0.5;
    		} else {
    			dy = dy > -0.5 ? 0 : dy + 0.5;
    		}
    	}
    
    	//After all that, apply these to the object
    	square.x += dx;
    	square.y += dy;
    }
    

    If you’re unfamiliar with the ternary operator, grab a piece of paper and a pen and write out a few of them in if…else format; it’s a great exercise to get to grips with that’s going on.

    Keep in mind I manipulate the dx and dy variables, and only set the actual x and y values at the end. This helps us make the motion fluid; it’s not jerking around as we alter their values directly throughout the function..

    Go on, test it! See how nicely it’s moving?


    Step 7: Handling Boundary Collisions

    Okay. Everything is right, moving fluidly – but OUT of the stage! Below I added the collision detection conditions.

    
    
    private function refresh(e:Event):void {
    	//Key Handler
    	if (Input.kd("A", "LEFT")) {
    		//Move to the left
    		dx = dx < 0.5 - _max ? _max * -1 : dx - 0.5;
    	}
    	if (Input.kd("D", "RIGHT")) {
    		//Move to the right
    		dx = dx > _max - 0.5 ? _max : dx + 0.5;
    	}
    
    	if (!Input.kd("A", "LEFT", "D", "RIGHT")) {
    		//If there is no left/right pressed
    		if (dx > 0.5) {
    			dx = dx < 0.5 ? 0 : dx - 0.5;
    		} else {
    			dx = dx > -0.5 ? 0 : dx + 0.5;
    		}
    	}
    
    	if (Input.kd("W", "UP")) {
    		//Move up
    		dy = dy < 0.5 - _max ? _max * -1 : dy - 0.5;
    	}
    	if (Input.kd("S", "DOWN")) {
    		//Move down
    		dy = dy > _max - 0.5 ? _max : dy + 0.5;
    	}
    
    	if (!Input.kd("W", "UP", "S", "DOWN")) {
    		//If there is no up/down action
    		if (dy > 0.5) {
    			dy = dy < 0.5 ? 0 : dy - 0.5;
    		} else {
    			dy = dy > -0.5 ? 0 : dy + 0.5;
    		}
    	}
    
    	//Boundary detection
    	if (square.x - dx < 0 || square.x + dx + square.width > stage.stageWidth) {
    		//x axis detection
    	}
    
    	if (square.y - dy < 0 || square.y + dy + square.height > stage.stageHeight) {
    		//y axis detection
    	}
    
    	//After all that, apply these to the object
    	square.x += dx;
    	square.y += dy;
    }
    

    It’s looking for boundaries in a more precise fashion, by checking whether the edges of the square hit the boundaries (before this, it was just checking the center of the square against the boundaries).

    Great. Now we need to add the code to make the square bounce off the boundaries. What I do for that is multiply by -1 the axis value dx or dy. But that is not enough! If the speed is quite fast, then the square will get through the margins or just go nuts. So before we multiply we need to set the x or y of the object to be the same as the boundary that it meets.

    So if x < 0 (and so it is colliding with the left edge), then we move the object to be exactly on the left edge, like so: object.x = 0; and then multiply the dx by -1.

    
    
    //Margin detection
    if (square.x - dx < 0 || square.x + dx + square.width > stage.stageWidth) {
    	//x axis detection
    	square.x = square.x - dx < 0 ? 0 : stage.stageWidth - square.width;
    	dx *= -1;
    }
    
    if (square.y - dy < 0 || square.y + dy + square.height > stage.stageHeight) {
    	//y axis detection
    	square.y = square.y - dy < 0 ? 0 : stage.stageHeight - square.height;
    	dy *= -1;
    }
    

    Test it now! Bouncy right? :)

    To make it even better, go on experimenting with different values - like instead of multiplying by -1, try -0.7 and see the results.


    Conclusion

    So you met the Input.as Class, got to know how to work with it, and made a nice fluid movement in just a few minutes. I think this counts as a great time!

    Please leave your comments below and any other questions, I will gladly answer.

    But if you encounter any problem please check twice your code, compare it with the source file and then if you can't make it work, feel free to post a question.


  2. Benjamin Reid says:
    January 23, 2012 at 10:13 pm

    As HTML games begin to gradually increase in popularity, vendors are starting to introduce some exciting new APIs to make gaming that little bit sweeter for both us developers and our end players. One of these is the GamepadAPI, which allows you to connect your good old console gamepad into your computer and use it for browser based games, plug and play style. Let’s dive in!


    Introduction: What Is the Gamepad API?

    In a nutshell, the Gamepad API allows you to interact with your browser using a video game console controller, AKA a gamepad. This doesn’t require a special driver or plugin to work, it’s as simple as plug and play!

    Being a console gamer rather than a desktop gamer myself, I much prefer to interact with games using a gamepad, and with the upcoming rise of HTML and JavaScript based games, this is going to become a really useful tool in making games more easily accessible for your users.

    The Gamepad API is not readily available for public release, but we can start using it for ourselves with preview versions of Firefox. So before we get stuck in, we need a few things.


    What You’ll Need

    As I mentioned, the Gamepad API isn’t available for public release just yet so you will need to first get yourself a Nightly build of Firefox and make sure you have the Firebug add-on installed (for debugging purposes only).

    Also, you can’t forget a gamepad! I’m going to be using a PlayStation 3 controller for this tutorial but an Xbox controller will do just fine.

    • Nightly – Downloads for Windows, Mac and Linux
    • Firebug – Download
    • A gamepad – PlayStation or Xbox controller will do
    • A USB cable to connect your controller to your computer

    Once you have installed Nightly and added on Firebug you are ready to go!

    (NB. Recent builds of Chromium have Gamepad API support as well, but this tutorial has not been tested against them.)


    Step 1: Connecting a Gamepad to Your Browser

    Let’s start with a basic HTML file (index.html), sourcing “gamepad.js” (a blank JavaScript file).

    index.html

    
    
    <!doctype html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>Introduction to the Gamepad API</title>
      </head>
      <body>
        <h1>Gamepad API</h1>
    
        <script src="gamepad.js"></script>
      </body>
    </html>
    

    The connection of a gamepad is detected with a simple JavaScript event listener, the event fired is called “MozGamepadConnected”. So the first thing we need to do is add an event listener to the window to detect that event.

    I’m also adding a callback function that will log the details of the event to Firebug’s console. This is the information we are most interested in and what will actually let us know that we have connected a gamepad successfully.

    
    
    function gamepadConnected(evt)
    {
      console.log(evt);
    }
    window.addEventListener('MozGamepadConnected', gamepadConnected);
    

    Run your index.html in Nightly and open up Firebug’s console, here we’ll be able to see the logging of the event from our callback function.

    Make sure your controller is turned off and not connected wirelessly to a games console. Plug it in to your computer via USB and power on the controller, watching the event log in the console.

    The logged event of connecting a gamepad

    Great, we have a gamepad connecting to a browser, no extra plugins or drivers required!


    Step 2: Disconnecting a Gamepad

    It’s just as important to know whether a gamepad has been disconnected as well, so let’s look at the event, “MozGamepadDisconnected”.

    Similarly to step one, add an event listener for a disconnect event and a callback function to log the event details.

    
    
    function gamepadDisconnected(evt)
    {
      console.log(evt);
    }
    window.addEventListener('MozGamepadDisconnected', gamepadDisconnected);
    

    If you’re gamepad is still connected, refresh your page (which you’ll see connected event be logged) and then disconnect your gamepad by ejecting it from the USB port. You should get an event log like this one.

    The logged event of disconnecting a gamepad

    Now we know when a gamepad has been connected and disconnected, it’s probably a good idea to record the state inside a variable and get ready to detect button events!

    
    
    var gamepadActive = false;
    
    function gamepadConnected(evt)
    {
      console.log(evt);
      gamepadActive = true;
    }
    function gamepadDisconnected(evt)
    {
      console.log(evt);
      gamepadActive = false;
    }
    
    window.addEventListener('MozGamepadConnected', gamepadConnected);
    window.addEventListener('MozGamepadDisconnected', gamepadDisconnected);
    

    Step 3: Detecting Button Presses

    Button presses, again, use an event listener and callback function with two events, “MozGamepadButtonDown” and “MozGamepadButtonUp”.

    I would suggest logging the entire event from the button press yourself to see what is going on, but the key piece of information we need to get from this event is evt.button. This is the numerical id of the button that was pressed.

    The callback function this time takes a second parameter, a boolean value to test if the button was pressed or released. We set this ourselves in the callback functions of the event listeners.

    
    
    function buttonPressed(evt, pressed)
    {
      console.log(evt.button, pressed);
    }
    window.addEventListener("MozGamepadButtonDown", function(evt) { buttonPressed(evt, true); } );
    window.addEventListener("MozGamepadButtonUp", function(evt) { buttonPressed(evt, false); } );
    

    This should now output the IDs of the buttons that are pressed and whether they were pressed or released (true for button down, false for button up).

    The logged button id's

    Next we’ll create an array with all the PlayStation 3 buttons in. The indices of the array will map to the IDs used on this gamepad, with the values being the name of the button.

    
    
    var gamepadActive = false,
        ps3Buttons = new Array();
    
    ps3Buttons[12]  = 'triangle',
    ps3Buttons[15]  = 'square',
    ps3Buttons[14]  = 'cross',
    ps3Buttons[13]  = 'circle',
    ps3Buttons[4]   = 'up',
    ps3Buttons[7]   = 'left',
    ps3Buttons[6]   = 'down',
    ps3Buttons[5]   = 'right',
    ps3Buttons[10]  = 'L1',
    ps3Buttons[8]   = 'L2',
    ps3Buttons[11]  = 'R1',
    ps3Buttons[9]   = 'R2',
    ps3Buttons[1]   = 'L3',
    ps3Buttons[2]   = 'R3',
    ps3Buttons[16]  = 'PS',
    ps3Buttons[0]   = 'select',
    ps3Buttons[3]   = 'start';
    

    If you’re using a different controller, take the time to figure out which index goes with which button, and store that info in a similar array.

    If we now modify the buttonPressed() function ever so slightly, we can easily tell which button on the controller has been pressed.

    
    
    function buttonPressed(evt, pressed)
    {
      console.log(ps3Buttons[evt.button] + ' was pressed');
    }
    

    Give it a go! Pressing buttons on your controller should now log the name of buttons being pressed. This will be a lot easier to understand than “button 5″ (which, in my case, is on the D-pad).


    Step 4: Detecting Axis Events

    Detecting axis events is basically keeping track of where the left and right analog sticks on the gamepad are positioned using the “MozGamepadAxisMove” event.

    Add the new event handler and callback function.

    
    
    function moveAnalogSticks(evt) {
      console.log(evt.axis, evt.value);
    }
    window.addEventListener("MozGamepadAxisMove", moveAnalogSticks);
    

    This is what we get – confusing, right?

    The logged button id's

    There is only one event fired by both analog sticks; each event gives us one of four possible axis and a value between -1.0 and +1.0. Axis 0 and 1 belong to left analog stick and axis 2 and 3 belong to the right.

    The logged button id's

    In the diagram above you’ll see axis 0 and 2 correspond to the x axis, and 1 and 3 correspond to the y axis. By using both the x and y axis for each individual analog stick, you can figure out which way the analog stick is facing!

    On different gamepads, you may have other axes. For instance, the shoulder triggers on an Xbox controller are also analog.


    Step 5: Putting It Into Practice

    That covers all of the events that we can currently take from a gamepad, so let’s put what we’ve learnt into practice.

    Now, I don’t want to go too heavily into the game development side of things, as we are focusing on what we use to control games themselves. One of the key things to look at, though, is switching control schemes. As not everyone will have a gamepad ready to hand, we need to make sure we provide controls for both the keyboard and gamepad.


    Step 6: Setting Up Your Canvas

    To get a small demo up and running, create a canvas element in your html file with an id of “game” and set the width to 600 and height to 540. As you may know, the canvas element is commonly used to render HTML games on.

    You will also want to copy the “ship.png” and “space.jpg” images from the source download to your working folder as these are what we’ll be rendering to the canvas. Alternatively, find some graphics of your own to have a play with!

    
    
    <!doctype html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>Introduction to the Gamepad API</title>
      </head>
      <body>
        <h1>Gamepad API</h1>
        <canvas id="game" width="600" height="540"></canvas>
        <script src="gamepad.js"></script>
      </body>
    </html>
    

    Step 7: Creating the Game Loop

    Now that the canvas element is in our DOM, we want to create a game loop to render our game.

    I’m using a shim for “requestAnimationFrame” by Paul Irish that will be the base for our loop. Next, we get the 2D context of the canvas which we’ll use to draw on and create two new image objects, one for the background and one for our spaceship.

    
    
    // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
    window.requestAnimFrame = (function(){
      return  window.requestAnimationFrame       ||
              window.webkitRequestAnimationFrame ||
              window.mozRequestAnimationFrame    ||
              window.oRequestAnimationFrame      ||
              window.msRequestAnimationFrame     ||
              function(/* function */ callback, /* DOMElement */ element){
                window.setTimeout(callback, 1000 / 60);
              };
    })();
    
    var canvas  = document.getElementById('game'),
        ctx     = canvas.getContext('2d'),
        ship    = new Image(),
        space   = new Image();
    
    space.src = "space.jpg";
    ship.src  = "ship.png";
    

    Next, the player object. It has x and y coordinates which keep track of where it should appear on the canvas; four direction states (up, down, left and right) so we can know which way the ship is moving; a render() function, which first calls updatePosition() and then draws the image of the ship onto the canvas based on the x and y coordinates, and finally the updatePosition() function itself, which tests to see which way the ship is set to move and updates its position accordingly.

    
    
    var player = {
      x: 200,
      y: 250,
      up: false,
      down: false,
      left: false,
      right: false,
      render: function() {
        this.updatePosition();
        ctx.drawImage(ship,this.x,this.y);
      },
      updatePosition: function() {
        this.up     ? this.y-- : false;
        this.down   ? this.y++ : false;
        this.left   ? this.x-- : false;
        this.right  ? this.x++ : false;
      }
    }
    

    After that we have our “renderGame” function which draws the space background image onto the canvas first, then draws our spaceship on top of that.

    And finally, our loop. This function calls itself again and again, each time calling our “renderGame” function.

    
    
    function renderGame()
    {
      ctx.drawImage(space,0,0);
      player.render();
    }
    
    ;(function animloop(){
      requestAnimFrame(animloop);
      renderGame();
    })();
    

    Your canvas should now have a nice space looking background with a spaceship sat in the middle of it – not too exciting, I know. So let’s add some controls!


    Step 8: Hooking Up the Ship’s Controls

    In our player code we named the four buttons which we want to control our ship with. These match up to the names of the buttons inside the ps3Buttons[] array. So, all we have to do is modify our buttonPressed() function ever so slightly and we’ll be moving.

    
    
    var player = {
      ...
      up: false,
      down: false,
      left: false,
      right: false,
      ...
    }
    

    Now when a gamepad button is pressed or released it will set its state within the player object, so when the “up” button is pressed, player.up = true/false will be set.

    
    
    function buttonPressed(evt, pressed)
    {
      console.log(evt.button, pressed);
      player[ps3Buttons[evt.button]] = pressed ? true : false;
    }
    

    Head back over to your demo and you should be able to move your ship around!


    Step 9: Adding a Keyboard Fallback

    As not everyone playing your game will have a gamepad, you’ll probably still want to allow them to play the game with a keyboard.

    Lets first create a new keys[] array, and map the keyboard’s arrow keys’ keyCode properties to the equivalent buttons on the gamepad. This will allow us to reuse buttonPressed() function that the gamepad utilises.

    
    
    var gamepadActive = false,
        ps3Buttons    = new Array(),
        keys          = new Array();
    
    ps3Buttons[12]  = 'triangle',
    ps3Buttons[15]  = 'square',
    ps3Buttons[14]  = 'cross',
    ps3Buttons[13]  = 'circle',
    ps3Buttons[4]   = 'up',
    ps3Buttons[7]   = 'left',
    ps3Buttons[6]   = 'down',
    ps3Buttons[5]   = 'right',
    ps3Buttons[10]  = 'L1',
    ps3Buttons[8]   = 'L2',
    ps3Buttons[11]  = 'R1',
    ps3Buttons[9]   = 'R2',
    ps3Buttons[1]   = 'L3',
    ps3Buttons[2]   = 'R3',
    ps3Buttons[16]  = 'PS',
    ps3Buttons[0]   = 'select',
    ps3Buttons[3]   = 'start';
    
    keys[38] = 4;
    keys[37] = 7;
    keys[40] = 6;
    keys[39] = 5;
    

    Now we need a “onkeyup” and “onkeydown” event listener for the arrow keys. When a key is pressed or released, we make sure that a gamepad is not in use. Then we prevent the arrow key from doing its usual task (scrolling the browser window up or down in this case) and then call the same buttonPressed() function that the gamepad calls.

    To do this, a fake event object is passed with the key’s “keyCode” mapped to an item in the keys[] array, which in turn, passes the corresponding gamepad button ID.

    
    
    window.onkeydown = function(evt)
      {
        if (gamepadActive == false)
        {
          evt.preventDefault();
          buttonPressed({ button: keys[evt.keyCode] }, true);
        }
      }
    window.onkeyup = function(evt)
      {
        if (gamepadActive == false)
        {
          evt.preventDefault();
          buttonPressed({ button: keys[evt.keyCode] }, false);
        }
      }
    

    This should now let you use the arrow keys for controlling the ship when a gamepad isn’t plugged in, while still letting the gamepad take over when it’s present.


    Conclusion

    So we’ve covered the basics of connecting a gamepad to your computer, learnt how to hook into the events that the gamepad fires, and then use them in practice. Not forgetting, the crucial fall-back support for the keyboard!

    A quick challenge for those of you with a controller other than a PS3 Dual Shock: adjust the button mapping based on whichever controller is plugged in.

    Thank you for taking the time to learn about the Gamepad API. If you have any questions, please leave them in the comments.


  3. Kah Shiu Chong says:
    January 23, 2012 at 10:57 pm

    In the previous Quick Tips, we’ve looked at collision detection: essentially, detecting that two shapes have overlapped. Now, we’re ready to look at collision reaction: making something happen due to a collision. In this Quick Tip, we’ll look at the reactions of reflection and sliding.


    Final Result Preview

    Let’s look at the end result we’ll achieve at the end of this tutorial. Each Flash demo has a restart button; click it to reset the position of the circles at the top of stage.

    The first demo shows off reflection:

    The second shows sliding:


    Step 1: The Reflection Formula

    I’ve run through this topic several rounds with students, and experience has taught me that the head-on approach of explaining vector math to freshers results in blank faces and confused minds. So instead of putting up a Math lecture here, I shall refer those who are interested in investigating this topic further to Wolfram’s page on reflection.

    Here, I shall simplify my explanations with diagrams below. Recall vector addition:

    Vector addition

    Now, observe the diagram below. A is the circle’s velocity before a collision, and A’ is its velocity after the collision.

    Reflection

    It’s obvious that A' = A + 2 V(Ap), where V(Ap) represents the vector with a magnitude of Ap, in the direction of the left normal. (You can see this by following the dashed lines.)

    In order to obtain V(Ap), we shall project A onto the left normal.


    Step 2: Implementation

    Here comes the ActionScript implementation of reflection. I’ve highlighted the important parts. Line 67 – 69 is to calculate V(Ap) (v_leftNormSeg2) and line 70 implements the formula. You may refer to the full Actionscript under Reaction1.as.

    (You should recognise most of the code from the previous Quick Tip.)

    
    
    private function refresh(e:Event):void {
    	for (var i:int = 0; i < circles.length; i++) {
    
    		//calculating line's perpendicular distance to ball
    		var c1_circle:Vector2D = new Vector2D(circles[i].x - x1, circles[i].y - y1);
    		var c1_circle_onNormal:Number = c1_circle.projectionOn(leftNormal);
    		var c1_circle_onLine:Number = c1_circle.projectionOn(line); 
    
    		//if collision happened, undo movement
    		if (Math.abs(c1_circle_onNormal) <= circles[i].radius
    			&& line.dotProduct(c1_circle) > 0
    			&& c1_circle_onLine < line.getMagnitude()){
    
    			//redefine velocity
    			var v_leftNormSeg2:Vector2D = leftNormal.clone();
    			var leftNormSeg2_mag:Number = Math.abs(velos[i].projectionOn(leftNormal))
    			v_leftNormSeg2.setMagnitude(leftNormSeg2_mag);
    			velos[i] = velos[i].add(v_leftNormSeg2.multiply(2));
    		}
    	circles[i].x += velos[i].x;
    	circles[i].y += velos[i].y;
    	}
    }
    

    Step 3: An Interactive Version

    Take note that this reflection formula is applicable to line of any gradient. In fact, you can program your line to be adjustable at runtime and see it reflecting circles like the Flash presentation below. Just click and drag near the lower end of the to redefine it.


    Step 4: Sliding Along Line

    The concept of sliding along the line is almost identical to reflection. Observe the diagram below.

    Sliding along

    The vector of slide is A' = A + V(Ap) with V(Ap) representing a vector with magnitude of Ap. Again, to obtain Ap we shall project A onto the left normal.

    Note that as the circle is sliding along the line, it is colliding with the line. Of course, collision points differ among circles that collide onto line, so some overlap the line as they move along it. This doesn’t look good, so we’ll have to reposition them.


    Step 5: Redefine Location

    Now, let’s reposition circles on the line while maintaining their contact with line. Refer to the diagram below.

    Reposition circle on line

    An important variable to calculate is the projection of A along line. The radius of circle is readily available, and we already have B, so we can form the vectors of B and C. Adding the two will give us A, the exact location to reposition circle. Simple!

    Vector calculation of the exact location

    The Flash presentation below is coded according to the mentioned idea. But there is one problem: the circles jitter along the line.

    There’s one final detail we missed. Diagram above shows magnitude of C should be equivalent to radius of circle. However, this will position circle back above the line. Since there’s no collision detected there, the circle will fall onto the line again, which in turn will flag the collision detection and cause the circle to be repositioned.

    This cycle will repeat until the is past the end of the line segment; the visual result of this cycle is the jittering effect.

    The solution to this problem is to set the magnitude of C to slightly less than the radius of the circle: (radius of circle - 1), say. Observe the Flash demo below which uses this idea:


    Step 6: Implementation

    So here’s the important ActionScript snippet for sliding along the line. I’ve highlighted the important parts.

    
    
    private function refresh(e:Event):void {
    	for (var i:int = 0; i < circles.length; i++) {
    
    		//calculating line's perpendicular distance to ball
    		var c1_circle:Vector2D = new Vector2D(circles[i].x - x1, circles[i].y - y1);
    		var c1_circle_onNormal:Number = c1_circle.projectionOn(leftNormal);
    		var c1_circle_onLine:Number = c1_circle.projectionOn(line); 
    
    		//check for collision
    		if (Math.abs(c1_circle_onNormal) <= circles[i].radius){
    
    			//check if within segment
    			//if within segment, reposition and recalculate velocity
    			if (line.dotProduct(c1_circle) > 0 && c1_circle_onLine < line.getMagnitude()) {
    
    				//repostion circle
    				var v_lineSeg:Vector2D = line.clone();
    				v_lineSeg.setMagnitude(c1_circle_onLine);
    				var v_leftNormSeg1:Vector2D = leftNormal.clone();
    				v_leftNormSeg1.setMagnitude(circles[i].radius - 1);
    				//v_leftNormSeg1.setMagnitude(circles[i].radius); //uncomment this to check out the error: jittering effect
    
    				var reposition:Vector2D = v_lineSeg.add(v_leftNormSeg1)
    				circles[i].x = x1+reposition.x;
    				circles[i].y = y1+reposition.y;
    
    				//redefine velocity
    				var v_leftNormSeg2:Vector2D = leftNormal.clone();
    				var leftNormSeg2_mag:Number = Math.abs(velos[i].projectionOn(leftNormal))
    				v_leftNormSeg2.setMagnitude(leftNormSeg2_mag);
    				var veloAlongLine:Vector2D = velos[i].add(v_leftNormSeg2);
    
    				circles[i].x += veloAlongLine.x;
    				circles[i].y += veloAlongLine.y;
    			}
    
    			//if not in segment (e.g. slide out of segment), continue to fall down
    			else {
    				circles[i].x += velos[i].x;
    				circles[i].y += velos[i].y;
    			}
    		}
    
    		//No collision in the first place, fall down
    		else {
    			circles[i].x += velos[i].x;
    			circles[i].y += velos[i].y;
    		}
    	}
    }
    

    Conclusion

    Hope this is helpful. Thanks for reading. Prompt me if there are questions, and I’ll see you next Quick Tip.


  4. James Tyner says:
    January 23, 2012 at 11:13 pm

    In this tutorial I will introduce you to FZip, an AS3 Library that lets you open zip files inside your Flash projects. This can save a lot of bandwidth; in this tutorial we will load an 2.5MB zip file which contains 9.3MB worth of assets.


    Final Result Preview

    Let’s take a look at the final result we will be working towards. Click here to open a SWF that will in turn load a zip file full of images, and display them in a tiled grid.

    (The blurring visible on some icons is due to Flash automatically attempting to scale them up to 32x32px, even though those particular images are 16x16px.)


    Step 1: Getting the Library and Zip Archive

    You will need to grad a copy of the FZip library from Claus Wahlers’ github.

    Extract the library. Inside the src folder there is a folder named “deng”; copy this folder to the folder where you will store your FLA.

    Next we need a zip archive to work with. I choose the WooFunction icon set, available for free from woothemes.com.

    Save this to the same directory where you will store your FLA.


    Step 2: Create New Flash Document

    Open a new FLA and give it the following properties:

    • Size: 550x400px
    • Background Color: White

    Save this as fzip.fla.


    Step 3: Add Components to Stage

    Go to Window > Components and drag a TileList component to the stage.

    Under “Component Parameters” set the following properties:

    • columnCount: 16
    • columnWidth: 32
    • rowCount: 8
    • rowHeight:32

    Give the TileList the instance name imageTileList, and set the following properties in the “Position and Size” panel:

    • X: 20
    • Y: 68
    • W: 100
    • H: 100

    Next select the Text Tool and make sure the following properties are set in the “Character” panel:

    • Size: 50pt
    • Color: Black

    Now drag a TextField onto the stage, and give it the instance name imagesLoaded. Make sure the TextField is set to “Classic Text” and “Dynamic Text”, respectively, and set the following properties:

    • X: 54
    • Y: 161
    • W: 454
    • H: 60

    Step 4: Create new AS3 Document

    Go to File > New and choose “Actionscript File”.

    Save this file as Main.as.


    Step 5: Package, Imports and Constructor

    Inside Main.as add the following:

    
    
    private function demonstrate():void
    package  {
    
    	import flash.display.MovieClip;
    	import deng.fzip.FZip;
    	import deng.fzip.FZipFile;
    	import flash.display.Loader;
    	import flash.net.URLRequest;
    	import flash.events.*;
    	import  fl.controls.TileList;
    	import fl.data.DataProvider;
    
    	public class Main extends MovieClip {
    
    		public function Main() {
    			setupZip();
    		}
    	 }
    }
    

    Here we imported the classes we will need for this tutorial, and set up the Main() constructor function.


    Step 6: Add Variables

    Define the following variables above public function Main():

    
    
    private var zip:FZip; // Instance of FZIP class
    private var numFiles:int = 0; //Number of files
    private var numFilesLoaded:int = 0; //Number of files loaded
    private var done:Boolean = false; //Done processing zip archive?
    private var tileListDp:DataProvider = new DataProvider();//Data provider for the TileList
    

    Here we add some variables we will need throughout the tutorial. See the comments for their usage.


    Step 7: setupZip()

    Add the following new function below Main():

    
    
    private function setupZip():void{
    	zip = new FZip();
    	zip.addEventListener(Event.OPEN, onOpen);
    	zip.addEventListener(Event.COMPLETE, onComplete);
    	zip.load(new URLRequest("wootheme.zip"));	//change this to match your zip file's URL
    	imageTileList.visible = false;
    }
    

    Here we create a new instance of the FZip class, add two event listeners, and load our zip file. Last, we set imageTileList to be invisible (We don’t want it to show until all the images from the zip have loaded).


    Step 8: onOpen()

    Add the following new function beneath the setupFzip() function you entered above:

    
    
    private function onOpen(evt:Event):void {
    	addEventListener(Event.ENTER_FRAME, onEnterFrame);
    }
    

    This function gets called when the zip archive has been opened. Here we add an ENTER_FRAME event listener.

    Step 9: onComplete()

    Add the following code new function beneath the onOpen() function you entered in the step above.

    
    
    private function onComplete(evt:Event):void {
    	done = true;
    }
    

    This function gets called when there are no more files to process from the zip archive.


    Step 10: onEnterFrame()

    Add the following beneath the onComplete() function you entered above. This function will be triggered every frame after the zip file has been opened:

    
    
    private function onEnterFrame(evt:Event):void {
        //Only load 32 files per frame, to save processing power
    	for(var i:uint = 0; i < 32; i++) {
    		// any new files available?
    		if(zip.getFileCount() > numFiles) {
    			//yes so get it
    			var file:FZipFile = zip.getFileAt(numFiles);
    			// is this a png in the icons folder?
    			if(file.filename.indexOf("woofunction-icons") == 0 && file.filename.indexOf(".png") != -1) {
    				var loader:Loader = new Loader();
    				loader.loadBytes(file.content);
    				tileListDp.addItem({source:loader});
    				numFilesLoaded++;
    			}
    			numFiles++;
    		} else {
    			// no new files available
    			// check if we're done
    			if(done) {
    				removeEventListener(Event.ENTER_FRAME, onEnterFrame);
    				removeChild(imagesLoaded);
    				imageTileList.visible = true;
    				imageTileList.dataProvider = tileListDp;
    			}
    			//Exit the Loop
    			break;
    		}
    	}
    	imagesLoaded.text = numFilesLoaded + " Images Loaded";
    }
    

    Here’s the meat of the code.

    Since this is running every frame, we’ll place an artificial restriction on the number of files within the archive that we deal with at once. That’s the purpose of the for-loop.

    zip.getFileCount() reveals how many files are in the zip; numFiles stores how many files we’ve dealt with so far. So, line 5 checks whether there are still more files to deal with.

    If there aren’t any files left, we skip to line 17 and just do some basic clearup: remove the ENTER_FRAME listener, remove the “loading” text field , make the tile list visible, and link it to the data.

    If there are files left, we get the next one in our list using numFiles as an index. We then check whether it’s a PNG from the icons folder; since we know the structure of the zip beforehand, we can cheat and just check whether the file’s name and path contains “woofunction-icons” and “.png”.

    To get the image from the zip and into a DisplayObject, we can use a Loader. This class is often used to load an image from a URL, but here we’re using its loadBytes() method to get the data from the ByteArray created by FZip.

    Since Loader extends DisplayObject, we can just add it straight to the TileList’s DataProvider. Then we increment both numFilesLoaded and numFiles.

    Why do we have two integers to keep track of how many files are loaded? Well, numFiles keeps count of all the files we’ve examined from the zip, whereas numFilesLoaded keeps count specifically of the image files that we’ve loaded into the DataProvider. It’s the latter variable that we use to update the “loading” text at the end of the function.


    Conclusion

    FZIP is an amazing little utility to save some loading time and bandwidth. I hope you’ve found this tutorial useful, and thanks for reading!


  5. Neil Wood says:
    January 23, 2012 at 11:37 pm

    Building real time networked games and applications can be challenging. This tutorial will show you how to connect flash clients using Cirrus, and introduce you to some vital techniques.


    Premium Preview

    Click the start button in the SWF above to create a ‘sending’ version of the application. Open this tutorial again in a second browser window, copy the nearId from the first window into the textbox, and then click Start to create a ‘receiving’ version of the application.

    In the ‘receiving’ version, you’ll see two rotating needles: one red, one blue. The blue needle is rotating of its own accord, at a steady rate of 90°/second. The red needle rotates to match the angle sent out by the ‘sending’ version.

    (If the red needle seems particularly laggy, try moving the browser windows so that you can see both SWFs at once. Flash Player runs EnterFrame events at a much lower rate when the browser window is in the background, so the ‘sending’ window transmits the new angle much less frequently.)


    Read the Full Tutorial

    Premium members can access the full tutorial right away!

    If you’re not yet a Premium member, you can still read the first few steps of the tutorial.


    Tuts+ Premium Membership

    We run a Premium membership system which periodically gives members access to extra tutorials, like this one! You’ll also get access to Psd Premium, Vector Premium, Audio Premium, Net Premium, Ae Premium, Cg Premium, Photo Premium, and the new Mobile Premium too. If you’re a Premium member, you can log in and download the tutorial. If you’re not a member, you can of course join today!

    Also, don’t forget to follow @envatoactive on twitter, circle us on Google+, like us on Facebook, and grab the Activetuts+ RSS Feed to stay up to date with the latest tutorials and articles.


  6. Jason Killian says:
    January 23, 2012 at 11:45 pm

    Building a button from a bitmap can be bothersome. If you’re using the Flash IDE, you can create a mask to determine which pixels are part of the button and which aren’t, but in any other workflow, the entire rectangle containing the bitmap – including any transparent pixels – will be clickable. In this tutorial, you’ll learn how to automatically make all transparent pixels unclickable, with just a few lines of code.


    Final Result Preview

    Let’s take a look at the final result we will be working towards:

    Notice that the hand cursor only appears when hovering over the actual image; even the gaps in the hair don’t cause it to appear. And it’s not just for show: the button presses only register when clicking on these areas.


    Introduction: What’s So Special?

    At a first glance, the SWF above appears extremely simple. But look closer! Notice how in the demo above, a button press is only counted if you click somewhere on the actual image. This isn’t what would normally happen. Since a bitmap image is always a rectangle, clicking anywhere inside its rectangle normally would count as a button press. Take a look at the example below, where I have outlined the boundary rectangle of our image. Here, you can click anywhere inside the rectangle, including the transparent areas.

    As you can see, this is not what we want! For starters, a user could accidentally click the button when he doesn’t mean to. In addition, it looks strange when a hand cursor appears over blank space. In this tutorial, you’ll learn how to easily correct these problems.

    If you aren’t already familiar with Object-Oriented Programming or FlashDevelop, I recommend checking out the provided links before starting this tutorial.


    Step 1: Getting Started

    Open up FlashDevelop and create a new AS3 project (Project > New Project) and call it something like BitmapButtonProj. On the right, open up the src folder and double-click Main.as to open it. Add a new class to your project (right-click /src/ > Add > New Class) called BitmapButton


    Step 2: Embedding an Image

    We now need an image to work with. Here is the one I’m using:

    Face image for BitmapButton class

    To use a bitmap image (such as a .jpeg file or a .png file) in Actionscript 3, we have to embed it. FlashDevelop makes this easy. After saving the above image somewhere, right-click the lib folder on the right, mouse over Add, and select the Library Asset option.

    How to add an image to the library in FlashDevelop

    If you want to use your own image, be sure to select one with transparency.

    The image you selected will now appear in the lib folder in FlashDevelop. Right-click the image and select Generate Embed Code.

    
    
    public class Main extends Sprite
    {
    	[Embed(source = "../lib/face.png")]
    	private var ButtonImg:Class;
    

    This code embeds the image in to our project. Whenever you embed an image, you need to define on the next line a class that represents the image you embedded. In this case, our class is called ButtonImg.


    Step 3: Adding a TextField

    Next, we’ll add a TextField to display how many times we have clicked the button (which will be added next). Add this to Main():

    
    
    clicksTextField = new TextField();
    clicksTextField.width = stage.stageWidth;
    clicksTextField.defaultTextFormat = new TextFormat(null, 14, 0, true, false, false, null, null, TextFormatAlign.CENTER);
    clicksTextField.text = "Button Presses: " + numClicks;
    clicksTextField.mouseEnabled = false;
    addChild(clicksTextField);
    

    The code above simply formats the text to display at the top center of our project. Don’t miss how we declared our TextField in line 15.


    Step 4: Adding the Button

    This code should also go in Main():

    
    
    var button:BitmapButton = new BitmapButton(ButtonImg);
    button.x = stage.stageWidth / 2 - button.width / 2;
    button.y = stage.stageHeight / 2 - button.height / 2;
    addChild(button);
    button.addEventListener(MouseEvent.CLICK,onButtonClick);
    

    When we instantiate our BitmapButton in line 36, we pass our embedded image class as a parameter. This will be used by the BitmapButton class. After this, we can simply treat our BitmapButton instance like any other DisplayObject: we can position it and add a MouseEvent.CLICK listener as we normally would.


    Step 5: Making the Button Do Something

    Add this event handler function to Main.as:

    
    
    private function onButtonClick(e:MouseEvent):void
    {
    	numClicks++;
    	clicksTextField.text = "Button Presses: " + numClicks;
    }
    

    The final piece of code in our Main class is the event listener for button clicks. In it, we simply add one to the number of clicks, numClicks, and update the text in clicksTextField.


    Step 6: The BitmapButton Constructor

    Flip over to BitmapButton.as. First, import these classes:

    
    
    	import flash.display.Bitmap;
    	import flash.display.BitmapData;
    	import flash.display.Sprite;
    	import flash.events.MouseEvent;
    

    Then, declare these:

    
    
    		private var bitmapData:BitmapData;
    		private const  THRESHOLD:Number = 0;
    

    You must make sure that the BitmapButton class extends Sprite, since a Bitmap by itself cannot have any mouse interactivity. (The Bitmap class doesn’t extend InteractiveObject.)

    
    
    public function BitmapButton(ImageData:Class)
    {
    	var image:Bitmap = new ImageData();
    	addChild(image);
    
    	bitmapData = image.bitmapData;
    
    	addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
    	addEventListener(MouseEvent.CLICK, onClick);
    }
    

    In our BitmapButton constructor, we accomplish a couple of important things.

    • First, we create a new Bitmap, called image, from the image class passed as a parameter to the constructor.
    • We then add this Bitmap as a child of our Sprite.
    • Next, we set the value of bitmapData to equal the bitmapData of our image.
    • Finally, we add CLICK and MOUSE_MOVE event listeners.

    Step 7: The MOUSE_MOVE Event Listener

    
    
    	private function onMouseMove(e:MouseEvent):void
    	{
    		var pixel:uint = bitmapData.getPixel32(mouseX, mouseY);
    		useHandCursor = buttonMode = ((pixel >>>24) > THRESHOLD);
    	}
    

    Our simple looking MOUSE_MOVE event listener is the real brains behind our class. Its main purpose is to determine whether the mouse cursor is over a transparent pixel or not. Let’s look at how it does this.

    The getPixel32() Function

    The first line gets the color and transparency of the pixel that the cursor is currently over. To do this, we use the getPixel32() method of the variable bitmapData (which, remember, is the bitmap data representation of our image).

    We must pass an x- and y-coordinate to getPixel32(), so naturally we use the mouse’s position.

    The call then returns a uint representing the color and transparency of the pixel at the location we supplied.

    Colors in Flash are normally treated as a hexadecimal uint in the format RRGGBB. The first two digits represent the amount of red in the color, the next two, green, and the final two, blue. However, getPixel32() provides us with a special uint representing our pixel in the format AARRGGBB. Here, the first two digits represent the alpha, or the amount of transparency, from 00 (clear) to FF (opaque).

    So, for example, FF980000 would represent a fully opaque red color, while 00980000 would represent a fully transparent red color. You’ll typically see these represented as 0xFF980000 or 0x0098000: the “0x” lets you (and Flash!) know that the number is in hexidecimal (0-f), rather than decimal (0-9).

    The Bitwise Unsigned Right Shift Operator

    At this point, we have a uint called pixel which is holding the color and alpha of the pixel beneath our mouse in the AARRGGBB format. Unfortunately, this is too much information. All we care about is the transparency of this pixel, or the AA part.

    You could write a mathematical expression to obtain this section – in fact, int(pixel/Math.pow(16,6)) would work. This is a somewhat awkward statement, though, and slower performance-wise than another option we have: the bitwise unsigned right shift operator, >>>.

    Our variable pixel is just a binary number to Flash. We normally write it in hexadecimal just to make it more readable. Without going into too much detail, every digit of a hexadecimal number can be represented by a string of four binary digits, each one either a 0 or a 1. (So, hexadecimal uses digits 0-f, decimal uses 0-9, and binary uses 0-1.)

    Say we have a hexadecimal number, D4. In binary, this would be represented as 11010100. Notice how we use eight binary digits for the binary representation: four times as many as in hexadecimal.

    With this is mind, let’s examine what the >>> operator actually does. Lets use our previous example, the hexadecimal number D4, or 0xD4 for clarity. Now let’s use >>> as so:

    
    
    0xD4 >>> 4
    

    Notice that 4 is a normal decimal representation of a number (there’s no “0x” at the start). This expression essentially shifts every binary digit in D4 four places to the right, and forgets about any digit that would go off the end of the number.

    0xD4, in binary, is 11010100. Apply four shifts, and it becomes 1101. In hexadecimal, this is 0xD.

    If you’re having trouble understanding this, imagine the binary digits as blocks sitting at the right side of a table. The >>> operator is just like pushing the blocks to the right. Here’s our original binary number:

    Binary representation of D4 before the bitwise shift is applied

    Now here’s our new number, after we do 0xD4 >>> 4 :

    Binary representation of D4 after the bitwise shift is applied

    Notice how after we shifted 0xD4 by 4 bits, we ended up with just 0xD? That’s not a coincidence. As said before, each hexadecimal digit is made up of 4 binary digits – so, each time we shift it to the right by 4, we essentially knock one hexadecimal digit off the end. You can probably see where we are going with this!

    Back to our pixel, in 0xAARRGGBB format. If we shift it by 24, we are actually shifting by 6 hexadecimal digits. This means the RRGGBB portion gets knocked off, and we end up with just the 0xAA part left, which is our alpha component.

    A quick numerical example: Say our pixel is equal to FF980000. In binary, this is 1111 1111 1001 1000 0000 0000 0000 0000. (Each group of 4 digits represents one hexadecimal digit.) When we shift this by 24, we simply end up with 1111 1111, or FF, our two transparency digits.

    Take a look at it again:

    
    
    useHandCursor = buttonMode = ((pixel >>> 24) > THRESHOLD);
    

    Okay, the (pixel >>> 24) part makes sense now, but what about the rest?

    It’s easy. We check whether our alpha component (the result of pixel >>> 24) is greater than the value of THRESHOLD (which is currently set to 0). If it is, useHandCursor and buttonMode are set to true, which will make the cursor change to a hand. This makes our image seem like a button.

    If our alpha component is less than or equal to THRESHOLD, the cursor will remain normal, since the mouse is over a (semi-)transparent pixel. Since we have it set to 0, only fully transparent pixels will not be included as part of our button, but you could set this to, say, 0×80, and then it would display the hand cursor for anything that’s more than half transparent.

    Step 8: The CLICK Event Listener

    
    
    private function onClick(e:MouseEvent):void
    {
    	if (!useHandCursor)
    	{
    		e.stopImmediatePropagation();
    	}
    }
    

    The final part of our BitmapButton class is the MouseEvent.CLICK event listener. This function will be called every time our image is clicked, no matter whether that pixel is transparent or not. (Changing the mouse cursor as we did before will not affect the actual MouseEvent.)

    So, every time there is a click, we check the useHandCursor property. If it is true, this means the mouse is over a normal pixel in our image, and we don’t need to do anything. This makes sense – the event will then continue on to the event listener we added in Main.as. However, if useHandCursor is false, we have to do something to stop the event from continuing on to other event listeners.

    For this, we use the stopImmediatePropagation() method that all Event objects have. Simply put, this stops the flow of the event, and no more event listeners will receive it. So, our event listener function in Main.as will never be called.

    Warning: this could have a nasty side effect – any global event listener will not get the event either. If you are worried about this, you can try adding the line parent.dispatchEvent(e.clone()); after e.stopImmediatePropogation(). While this is beyond the scope of the tutorial, I recommend reading more about the event system here.


    Conclusion

    This wraps up our tutorial! Thanks for reading, and I hope you have learned something new.

    A note of caution when using our BitmapButton class – other MouseEvents will still work as normal, since we only dealt with MouseEvent.CLICK. If you wanted, you could use the same technique we used for MouseEvent.CLICK and apply it to other events, such as MouseEvent.MOUSE_DOWN.

    Our BitmapButton class allows us to quickly and easily make great buttons from bitmap images with transparency, as we did in this demo. If you have any questions, I’ll be glad to answer them, just leave a comment below.


  7. Grant Friedman says:
    January 24, 2012 at 12:03 am

    Are you looking to start your new year with a fresh set of prints to help promote your design business? Today, our friends at UPrinting are kicking off 2012 by giving away business cards, posters, or postcards to 36 lucky Tuts+ readers. To enter, all you have to do is submit your entry using the form below and select which prize you would prefer.

    Update: The winners for this giveaway have been selected. Thanks to everyone who participated.

    If you are a frequent reader of our site, chances are, you are already familiar with UPrinting. They are an online printer that offers business cards, poster printing, postcard printing, and much more. UPrinting is a frequent sponsor of this site and we are very excited to partner with them on another giveaway.

    Submit Your Entry


    Up for Grabs

    Today, UPrinting is giving you several options to choose from. You can enter to win 500 standard business cards, 100 postcards, or 1 poster print. The choice is yours! More details can be found below.

    500 Standard Business Cards
    2" x 3.5" US Standard, 2" x 2" Square, 1.75" x 3.5" Slim
    14pt Cardstock Gloss / Matte, 13pt Cardstock Uncoated
    Front and Back Printing
    3 Business Days Turnaround time

    1 Poster Print
    18" x 24"
    Semi Gloss / High Gloss
    1 Business day print turnaround time

    100 Postcards
    5" x 7"
    14pt Cardstock Gloss
    Front Only Printing
    2 Business days print turnaround time


    Rules

    • To enter, submit your entry and select which product you would like.
    • You may only enter once.
    • Follow UPrinting on Twitter, Facebook, or Google+ (Optional)
    • Make sure to enter a valid email address so that we can contact you.
    • Entries will be accepted until Friday, January 20, 2012 at 11:59 PM, EST.
    • Shipping is free to U.S. and International residents.


  8. Kah Shiu Chong says:
    January 24, 2012 at 12:47 am

    We covered collision detection between an infinite line and circle in our previous Quick Tip. However, the issue that arose was that the line extends further than the visible line segment; in fact, it extends into a hyperplane. In this Quick Tip, we shall limit our collision detection to that of a line segment only.


    Final Result Preview

    We shall work toward this result:

    Click the Restart button to reposition the circles at the top of the stage.


    Step 1: Two Approaches

    There are numerous approaches to limit collision detection to within a line segment. We shall look at two approaches this time. The first approach is a little more rigorous mathematically than the second one, but these are concepts which, if you grasp successfully, will surely benefit you in the future. Both approaches manipulate the dot product’s characteristic of being a measure of how parallel two given vectors are.

    Let’s have a look at the first approach. Suppose A and B are vectors. If A and B are parallel – or at least pointing in the same direction – the dot product between A and B will produce a positive number. If A and B are pointing directly opposite each other – or at least pointing in opposing directions – the dot product between A and B will produce a negative number. If A and B are orthogonal (forming 90° to each other) then the dot product will produce 0.

    The diagram below summarises this description.

    Dot product as a measure of parallelism between vectors.

    Step 2: Relate Dot Product to Conditions

    We’ll need to form vectors B and C from both ends of the line segment so that their dot product with the line segment’s vector, A, can determine whether the circle is within the segment.

    Observe the diagram below. If the circle is within the segment, then the value of the dot product between A and B is positive and that between A and C is negative.

    Using dot product to define a segment.

    The diagram below shows how the dot product changes depending on whether the circle is beyond or within the line segment. Note the differences in the value of the dot product.

    A summary of all conditions.

    Also note that “within the line segment” does not mean that the circle is necessarily intersecting the line segment, just that it falls within the two thin lines on the diagram above.

    So when collision occurs between line and circle, as we have seen in the previous Quick Tip, we have to further investigate whether the circle is positioned within the line segment. If it is, then we know for sure that there is a genuine intersection.


    Step 3: Implementation

    Step 2 explained the concept we use to restrict collision detection to be within the line segment. However, there’s still a flaw in the precision. You see, the area defined is a little tilted; we should aim to use the area defined according to the diagram below.

    reorient the region.

    This is easy: we simply calculate D as the horizontal projection of A. Then, instead of using A, we use D to dot product with B and C. All the conditions as explained in Step 2 still stand, but instead of a tilted segment, we have defined a vertical area.

    This correction can be visually appreciated if the circle is large; if the circle were small, its center would be so close to the line that this visual flaw would be hard to detect, so we could get away with using that slightly tilted area and save ourselves some processing power.

    Nevertheless, I’ll try to do things the correct way. You can pick your approach by modifying the condition slightly.


    Step 4: Implementation

    The first Actionscript snippet here sets up vector D (v_line_onX)

    
    
    //Att2: getting the horizontal vector
    var line_onX:Number = line.projectionOn(new Vector2D(1, 0));
    v_line_onX = new Vector2D(1, 0);
    v_line_onX.setMagnitude(line_onX);
    

    Note: We’re using classes from my previous tutorials here. Vector2D was introduced in Gravity in Action, but you don’t need to read that to use the class, it’s included in the source download.

    The second Actionscript snippet here sets up B (c1_circle) and C (c2_circle) and checks for the collision and whether the circle is inside the segment or not.

    
    
    private function refresh(e:Event):void {
    	for (var i:int = 0; i < circles.length; i++) {
    
    		//calculating line's perpendicular distance to ball
    		var c1_circle:Vector2D = new Vector2D(circles[i].x - x1, circles[i].y - y1);
    		var c1_circle_onNormal:Number = c1_circle.projectionOn(leftNormal);
    
    		//Att2: get vector from c2 to circle
    		var c2_circle:Vector2D = new Vector2D(circles[i].x - x2, circles[i].y - y2);
    
    		circles[i].y += 2;
    
    		if (
    			c1_circle_onNormal <= circles[i].radius
    			&& v_line_onX.dotProduct(c1_circle) > 0
    			&& v_line_onX.dotProduct(c2_circle) < 0
    		){
    			//if collision happened, undo movement
    			circles[i].y -= 2;
    		}
    	}
    }
    

    Step 5: The Result

    Here’s the result for the first approach. Click on the button to reset positions of all circles to the top of stage.


    Step 6: Second Approach

    The second approach is much simpler. I’ll try to work backwards from the end this time around.

    Observe the diagram below. The line segment is from c1 to c2. It’s clear that collide1 and collide3 are both outside the line segment, and that only collide2 is within the line segment.

    Analysing the collision conditions.

    Let v1, v2 and v3 be vectors from c1 to respective circles. Only v2 and v3 are parallel – or at least pointing in similar directions to the line vector (c1 to c2). By checking for a positive value in the dot product between the line vector and each of those vectors from c1 to the corresponding circle centers (v1, v2, v3), we can easily determine that collide1 is beyond the line segment. In other words, c1 . v1 < 0.

    Analysing the collision conditions.

    Next, we shall devise a method to determine that collide3 is outside of the line segment. This should be easy. It's obvious that v3's projection along the line vector will exceed the length of line segment. We shall use this characteristic to weed off collide3.

    So let me summarise the second approach:

    • First we check for an intersection between the infinite line and the circle.
    • If there is an intersection, further investigate the following to determine whether it happens within the line segment:
      • Check that a positive value is produced when we take the dot product of the vector from c1 to circle and the line vector, and
      • Check that the magnitude of the projection of the vector along the line vector is shorter than the line segment's length.

    Step 7: Implementation

    Here's the ActionScript implementation of the above:

    
    
    private function refresh(e:Event):void {
    	for (var i:int = 0; i < circles.length; i++) {
    
    		//calculating line's perpendicular distance to ball
    		var c1_circle:Vector2D = new Vector2D(circles[i].x - x1, circles[i].y - y1);
    		var c1_circle_onNormal:Number = c1_circle.projectionOn(leftNormal);
    
    		//Att2: getting the relevant vectors
    		var c1_circle_onLine:Number = c1_circle.projectionOn(line);
    
    		circles[i].y += 2;
    
    		if (
    			Math.abs(c1_circle_onNormal) <= circles[i].radius
    			&& line.dotProduct(c1_circle) > 0
    			&& c1_circle_onLine < line.getMagnitude()
    		){
    			//if collision happened, undo movement
    			circles[i].y -= 2;
    		}
    	}
    }
    

    Step 8: The Result

    Essentially, it will produce the same result as the previous but since there is a few lines of code shorter in the second approach, I guess its better.

    Conclusion

    Hope this has helped. Thanks for reading. Next up, we'll look at collision reaction.


  9. Dru Kepple says:
    January 24, 2012 at 12:48 am

    Flash Player 10 introduced new low-level APIs for manipulating audio with AS3. In this tutorial, exclusive to Tuts+ Premium members, you’ll learn about these APIs and how they work, and use them to create a simple app that can play MP3s in reverse.


    Premium Preview

    description of image
    Click to view the demo

    Click here to view a preview of the SWF we’ll be building in this tutorial. Click on the “Play” button to play the sound. You can’t really tell by looking at or listening to it, but this isn’t just an MP3 loaded and then played normally; the MP3 is being used as a sound source and samples are fed dynamically to the Sound engine. To help prove it, the “Reverse” button will play the same sound, just in reverse. There is no sleight of hand here: there is only one MP3 loaded and the reversal effect is computed on the fly.

    If you’re not yet a Premium member, you can still read the first few steps of the tutorial. Members can, of course, access the full thing right away!


    Tuts+ Premium Membership

    We run a Premium membership system which periodically gives members access to extra tutorials, like this one! You’ll also get access to Psd Premium, Vector Premium, Audio Premium, Net Premium, Ae Premium, Cg Premium, Photo Premium, and the new Mobile Premium too. If you’re a Premium member, you can log in and download the tutorial. If you’re not a member, you can of course join today!

    Also, don’t forget to follow @envatoactive on twitter, circle us on Google+, like us on Facebook, and grab the Activetuts+ RSS Feed to stay up to date with the latest tutorials and articles.


  10. Tyler Seitz says:
    January 24, 2012 at 1:01 am

    Stop using static menus! Most players immediately base their initial impression of a Flash game on the menu that they see when they load it. Stand out from the crowd with an active menu!

    This tutorial was first posted in December 2011, but has since been updated with extra steps that explain how to make the code more flexible!


    Final Result Preview

    Introduction: Static vs Active

    The word “static” essentially means lacking in change. The majority of menus we see throughout web games are lacking in change, you simply press Play and the game starts. Menus like that are overused and show little creativity or innovation.

    To make a menu “active” we must continuously cause change. So in this tutorial that is exactly what we are going to accomplish: a menu that continuously changes.


    Step 1: Setting Up

    The first thing we are going to need to create is a new Flash File (ActionScript 3.0). Set its width to 650px, its height to 350px, and the frames per second to 30. The background color can be left as white.

    Now save the file; you can name it whatever you please, but I named mine menuSlides.fla.

    In the next section we will create the nine MovieClips used in the menu. For reference, here is a list of all the colors used throughout the tutorial:

    • White – #FFFFFF
    • Gold – #E8A317
    • Light Gold – #FBB917
    • Blue – #1569C7
    • Light Blue – #1389FF
    • Green – #347235
    • Light Green – #3E8F1B
    • Red – #990000
    • Light Red – #C10202
    • Matte Grey – #222222

    Step 2: Creating the Slide MovieClips

    To start with we will create the slides used in the transitions, but before we begin let’s turn on some very useful Flash features.

    Right-Click the stage and select Grid > Show Grid. By default it will create a 10px by 10px grid across the stage. Next, right-click the stage again and this time select Snapping > Snap to Grid.

    Now we can begin drawing! Select the Rectangle Tool and draw a Light Gold rectangle, 650px wide and 350px tall (you can Alt-click on the stage to make this easier). Now change the color to Gold and draw groups of three squares, each 20x20px, to form the shape of an L in each corner,:

    The basic Slide Design

    Select the whole stage, right-click and choose Convert to Symbol. Name the MovieClip goldSlide and make sure that the type is MovieClip and the registration is top-left.

    To save time and make things a whole lot easier, right-click the goldSlide MovieClip in the Library and select Duplicate Symbol three times to make three more copies. Change the colors in the new MovieClips to blue, green and red, then rename the MovieClips to blueSlide, greenSlide and redSlide.

    Before we continue we should add some text to each slide. On goldSlide write PLAY, on blueSlide write INSTRUCTIONS, on greenSlide write OPTIONS and on redSlide write CREDITS.

    Now that we have the text in place we can break it apart by right-clicking on it and selecting Break Apart twice; this will break the text down to a fill which will transition more smoothly. Plus as a bonus there will be no need to embed a font if you are just using it for the menu!

    The Buttons

    Now that we have drawn the 4 slides we can focus on the sideButton MovieClip that is used to move the slides either left or right.

    First, draw a rectangle 30x60px with only a stroke (no fill), then draw diagonal lines 45 degrees from the top-right and bottom-right corners until they snap together in the middle of the opposite side. Now apply a Matte Grey fill to the triangle:

    What your side Button Should Look Like

    Next, delete the lines, then right-click the triangle and select Convert to Symbol. Name it sideButton, set the type to Button and make sure the registration is in the top-left corner.

    Now insert 3 keyframes in the timeline by right-clicking the timeline and selecting Insert Keyframe. On the Up frame, select the fill of the triangle, go to the Windows tab and select Color. Change the Alpha to 50%. On the Over Frame repeat the same process, but this time set the alpha to 75%.

    Now we can begin on the four numbered circle buttons, for jumping directly to a particular slide.

    To start draw a white 30px circle with no stroke. Convert it to a symbol, name it circleOne, and set its type to Button and its registration point to the center. Insert three keyframes like we did before and then go to the Up frame.

    Draw a black 25px circle with no stroke and center it to the middle through the coordinates or by using the Align menu. Next deselect the black circle, then reselect it and delete it. You should now have a white ring remaining. Now grab the text tool and put a white “1″ in the center of the ring. Then break this number apart until it is a fill.

    circleOne Up Frame

    Go to the Over frame and draw a black “1″. Center it and break it apart until it becomes a fill. Now deselect and reselect the fill, then delete it. Select everything on the frame and copy it, then go to the Down frame, select everything on it and hit delete. Paste in what we have copied.

    circleOne Over Frame

    Now create three more circle MovieClips, following the same process, for the numbers 2, 3 and 4.


    Step 3: Positioning the MovieClips

    Okay, we’re almost half-way done! First drag all of the slides onto the stage and position them with the following coordinates:

    • goldSlide: (0, 0)
    • blueSlide: (650, 0)
    • greenSlide: (1300, 0)
    • redSlide: (1950, 0)

    Now drag and drop two copies of the sideButton. The first copy should be positioned at (10,145); before we can position the second copy we must first flip it!

    Select the second copy and press Ctrl-T. Change the left-right to -100% and leave the up-down at 100%. Now move the second copy to (640,145).

    Finally drag and drop the four circle MovieClips and position them as so:

    • circleOne: (30, 320)
    • circleTwo: (70, 320)
    • circleThree: (110, 320)
    • circleFour: (150, 320)

    Your stage should now look like this:

    What your stage Should Look Like

    The blue, green and red slides are hidden just off to the right of the stage. Now select everything on the stage and convert to a symbol. Name it menuSlidesMC, set the type to MovieClip and the registration to the top-left corner, and export it for ActionScript as MenuSlidesMC.

    Before we finish we must give each of the MovieClips inside menuSlidesMC an instance name. Select each slide in the order they appear from the left and name them slide1, slide2, slide3 and slide4 respectively. Name the circle buttons one, two, three and four, and finally name the side buttons left and right.


    Step 4: Setting Up the Classes

    Now that all of our MovieClips have been created we can start setting up the two classes we are going to use.

    First go to your Flash file’s Properties and set its class to menuSlides; then, create a new ActionScript 3.0 file and save it as menuSlides.as.

    Now copy the following code into it; I will explain it after:

    
    
    package{
    	import flash.display.MovieClip;
    	import flash.events.Event;
    	import flash.events.MouseEvent;
    
    	public class menuSlides extends MovieClip{
    		public var menuSlidesMC:MenuSlidesMC = new MenuSlidesMC();
    		public function menuSlides(){
    			addChild(menuSlidesMC);
    		}
    	}
    }
    

    Pretty basic – it’s a document class, into which we imported the MovieClips and Events we will use. Then we created an instance of MenuSlidesMC, and added it to the stage.

    Now create a new ActionScript 3.0 file for the menuSlidesMC instance. Save it as MenuSlidesMC.as and copy the following code into it:

    
    
    package{
    	import flash.display.MovieClip;
    	import flash.events.Event;
    	import flash.events.MouseEvent;
    
    	public class MenuSlidesMC extends MovieClip{
    		public var speed:Number = new Number();
    		public var activeSlide:Number = new Number();
    		public function MenuSlidesMC(){
    			speed = 10;
    			activeSlide = 1;
    			addEventListener(MouseEvent.CLICK, slidesClick);
    			addEventListener(Event.ENTER_FRAME, slidesMove);
    		}
    	}
    }
    

    Just like last time, we imported what we are going to need, but we created two number variables. The first variable, speed, is actually how many pixels the slides are moved by each frame. (Note: this number has to evenly divide into your stage’s width to give a smooth transition). The second variable, activeSlide, tells us which slide is currently set to be on screen.

    We also added two event listeners for functions we are going to create; one of them is called on a mouse click, and the other is called at the beginning of every frame.


    Step 5: Creating the Event Handler Functions

    To begin we will get the mouse click function out of the way. Start by creating a public function named slidesClick():

    
    
    public function slidesClick(event:MouseEvent):void {
    
    }
    

    Next we will create some if-statements regarding the event.target.name. Basically, this property stores the name of the object that was targeted by the mouse click. We can use this to check which button is pressed:

    
    
    if(event.target.name == "left"){
    	if(activeSlide>1){
    		activeSlide-=1;
    	}
    }else if(event.target.name == "right"){
    	if(activeSlide<4){
    		activeSlide+=1;
    	}
    }
    
    if(event.target.name == "one"){
    	activeSlide=1;
    }else if(event.target.name == "two"){
    	activeSlide=2;
    }if(event.target.name == "three"){
    	activeSlide=3;
    }else if(event.target.name == "four"){
    	activeSlide=4;
    }
    

    The code above goes in the slidesClick() function. The first set of if-statements are for the left and right side buttons; they increase or decrease the value of activeSlide, but never allow the value to become less than 1 or greater than 4 (since we only have four slides). The second set of if-statements are for the circle buttons; instead of just incrementing or decrementing the value of activeSlide they set it to the selected value.

    Now let’s begin with the ENTER_FRAME handler function:

    
    
    public function slidesMove(event:Event):void {
    
    }
    

    Add the slidesMove() function below your slidesClick() function and we’ll start adding some code to it. First, we’ll use a switch to check which slide should be on the screen, based on the value of activeSlide:

    
    
    switch (activeSlide){
    case 1:
    
    break;
    case 2:
    
    break;
    case 3:
    
    break;
    case 4:
    
    break;
    }
    

    Now in each case we will create an if/else block that will check that slide’s current x-position, and move all of the slides either left, right, or not at all, depending on where the desired slide currently sits.

    The first case looks like this:

    
    
    if(slide1.x<0){
    	slide1.x+=speed;
    	slide2.x+=speed;
    	slide3.x+=speed;
    	slide4.x+=speed;
    }else if(slide1.x>0){
    	slide1.x-=speed;
    	slide2.x-=speed;
    	slide3.x-=speed;
    	slide4.x-=speed;
    }
    

    Now all we have to do is repeat the same process for the other cases! After you are done your swtich should look like this:

    
    
    switch (activeSlide){
    	case 1:
    		if(slide1.x<0){
    			slide1.x+=speed;
    			slide2.x+=speed;
    			slide3.x+=speed;
    			slide4.x+=speed;
    		}else if(slide1.x>0){
    			slide1.x-=speed;
    			slide2.x-=speed;
    			slide3.x-=speed;
    			slide4.x-=speed;
    		}
    	break;
    	case 2:
    		if(slide2.x<0){
    			slide1.x+=speed;
    			slide2.x+=speed;
    			slide3.x+=speed;
    			slide4.x+=speed;
    		}else if(slide2.x>0){
    			slide1.x-=speed;
    			slide2.x-=speed;
    			slide3.x-=speed;
    			slide4.x-=speed;
    		}
    	break;
    	case 3:
    		if(slide3.x<0){
    			slide1.x+=speed;
    			slide2.x+=speed;
    			slide3.x+=speed;
    			slide4.x+=speed;
    		}else if(slide3.x>0){
    			slide1.x-=speed;
    			slide2.x-=speed;
    			slide3.x-=speed;
    			slide4.x-=speed;
    		}
    	break;
    	case 4:
    		if(slide4.x<0){
    			slide1.x+=speed;
    			slide2.x+=speed;
    			slide3.x+=speed;
    			slide4.x+=speed;
    		}else if(slide4.x>0){
    			slide1.x-=speed;
    			slide2.x-=speed;
    			slide3.x-=speed;
    			slide4.x-=speed;
    		}
    	break;
    }
    

    And that’s it! We are all finished with the code and the menu should be working great right now.

    …But wait, what if we want to add more slides or take some away?


    Step 6: Adding Slides to an Array

    At the moment our code isn’t very flexible due to all of those hard-coded if statements. So let’s do something bold: delete all of the code in the slidesMove() function because we will no longer be needing it, and also delete the if-statements for the circle buttons as we are going to optimize those as well.

    Now declare a new variable (underneath speed and activeSlides):

    
    
    public var slidesArray:Array = new Array();
    

    The first variable, slidesArray, will be an array that contains all of our slides, which will allow us to access them by referencing an item in the array (so we can use slidesArray[2] instead of slide3).

    One thing to note is that the first item in an array is given an index of 0, so we will have to make some changes to our instance names.

    Select each slide in the order they appear from the left and name them slide0, slide1, slide2 and slide3, respectively. And to help us cut down on the number of lines of code we use, select each circle button in the order they appear from the left and name them circle0, circle1, circle2 and circle3, respectively.

    If you are going to add more slides and buttons, now is the time to do so. Just position the extra slides at the end of the row of slides, then give them instance names following the same order. Then do the same for the circle buttons.

    Now that we have the instance names correct we must add the slides to the array. Do so by adding the following code to your constructor:

    
    
    slidesArray = [slide0, slide1, slide2, slide3, slide4, slide5];
    

    Now the slides are in the array and can be accessed by their index in the array. For example, slidesArray[0] is equivalent to slide0 because that is the first item in the list.

    Next, inside the “right” else-if statement, change the condition to:

    
    
    if(activeSlide < slidesArray.length-1){
    

    The value of slidesArray.length is equal to the number of elements in the array, so this new condition will now allow us to press the button and shift the slides over as long as the active slide is not the final slide.


    Step 7: Handling Circle Button Presses

    Now, when a circle button is clicked, we need to figure out which one it is (and which slide it refers to).

    Create an array to hold all the circle buttons. First, define it, beneath the slide array:

    
    
    		public var slidesArray:Array = new Array();
    		public var circlesArray:Array = new Array();
    

    Then, add the circle buttons to the array in the constructor:

    
    
    			circlesArray = [circle0, circle1, circle2, circle3, circle4, circle5];
    

    Now, move to the slidesClick() function, underneath the whole if-else block. We’re going to check whether the button clicked is in the circle buttons array:

    
    
    			if (circlesArray.indexOf(event.target) != -1) {
    
    			}
    

    The array’s indexOf() function checks to see whether an object is in the array; if it’s not, it returns -1. So, we’re checking to see whether it’s not equal to -1, which will check to see whether it is in the array.

    Assuming it is, then the indexOf() function will return the index of the button within the circle buttons array – so, if circle3 was clicked, circlesArray.indexOf(event.target) will be equal to 3. This means we can just set activeSlide to 3, and we’re done!

    
    
    			if (circlesArray.indexOf(event.target) != -1) {
    				activeSlide = circlesArray.indexOf(event.target);
    			}
    

    Step 8: Moving the Slides

    The only thing left to do is move all of the slides. Begin by adding the same loop as we had before, in the slidesMove() function:

    
    
    for(var i:int = 0; i < slidesArray.length; i++){
    
    }
    

    An if-else statement needs to be added now; this will use the variable activeSlide to select a slide out of the array and check where its x-position is, just like before.

    
    
    if(slidesArray[activeSlide].x<0){
    
    }else if(slidesArray[activeSlide].x>0){
    
    }
    

    Since activeSlide is a number, slidesArray[activeSlide] refers to one specific slide, so slidesArray[activeSlide].x is equal to that slide’s x-position.

    In the first case we will add a for loop to move all of the movie clips to the right, and in the second case we will add a for loop to move all of the movie clips to the left.

    Right:

    
    
    for(var j:int = 0; j < slidesArray.length; j++){
    	slidesArray[j].x+=speed;
    }
    

    Left:

    
    
    for(var k:int = 0; k < slidesArray.length; k++){
    	slidesArray[k].x-=speed;
    }
    

    If you test this now, you will notice that our optimised code has lead to a much zippier interface!


    Step 9: Taking It Further

    If you wanted to take this even further, you could use a for loop to position the slides and the circles, rather than needing to drag and drop them in the Flash IDE. For example, to position the slides, we’d first position slide0 in the constructor:

    
    
    			slidesArray = [slide0, slide1, slide2, slide3, slide4, slide5];
    			slidesArray[0].x = 0;
    			slidesArray[0].y = 0;
    

    Then, we’d loop through all the other slides, starting at slide1:

    
    
    			slidesArray = [slide0, slide1, slide2, slide3, slide4, slide5];
    			slidesArray[0].x = 0;
    			slidesArray[0].y = 0;
    			for (var i:int = 1; i < slidesArray.length; i++) {
    
    			}
    

    We can give all the slides an y-position of 0:

    
    
    			slidesArray = [slide0, slide1, slide2, slide3, slide4, slide5];
    			slidesArray[0].x = 0;
    			slidesArray[0].y = 0;
    			for (var i:int = 1; i < slidesArray.length; i++) {
    				slidesArray[i].y = 0;
    			}
    

    …and then we can set each slide’s x-position to be 620px to the right of the slide before it:

    
    
    			slidesArray = [slide0, slide1, slide2, slide3, slide4, slide5];
    			slidesArray[0].x = 0;
    			slidesArray[0].y = 0;
    			for (var i:int = 1; i < slidesArray.length; i++) {
    				slidesArray[i].x = slidesArray[i-1].x + 620;
    				slidesArray[i].y = 0;
    			}
    

    If your slides aren’t 620px wide, you can even detect their width automatically!

    
    
    			slidesArray = [slide0, slide1, slide2, slide3, slide4, slide5];
    			slidesArray[0].x = 0;
    			slidesArray[0].y = 0;
    			for (var i:int = 1; i < slidesArray.length; i++) {
    				slidesArray[i].x = slidesArray[i-1].x + slidesArray[i-1].width;
    				slidesArray[i].y = 0;
    			}
    

    You can do the same thing with the circle buttons, but I’ll leave that up to you to experiment with.

    The great thing about this is, you can add as many slides as you want to the menu; all you have to do is add them to the array, and they’ll be dealt with by this code.

    (You can remove slides from the array, too, but they won’t be affected by any of the code, so you’ll probably need to reposition them in the Flash IDE.)

    Conclusion

    Thank you for taking the time to read through the tutorial, I hope it was helpful and that you learned a little something about active game menus.


Leave a Reply

Click here to cancel reply.

search search search search search
Find an Article
Categories
  • Flash Video Training
  • Hints and Tips
  • Recommended
Please Support Our Sponsors
Recent Posts
  • The Math and ActionScript of Curves: Drawing Quadratic and Cubic Curves
  • Weekend Lecture: Understanding Games, a Flash Game About Game Design
  • Weekend Lecture: Understanding Games, a Flash Game About Game Design
  • Workshop Coding Challenge: Fix This Breakout Game
  • Enable the Latest AIR SDK in Flash Professional CS5.5+
Tag Cloud
2011 ActionScript Active Activetuts+ Adobe animation Basic Basix Best Build Button Character Create Creating Critique Custom design Effect Effects Files Flash from Game Guide HTML5 Introduction Macromedia Motion Muzzle part Player Premium Professional Quick Silverlight Simple Text Tool Tutorial Tuts+ Tween Using Video website Workshop
About Our Site:

Hey there and welcome to "Flash Video Training Source", a resource for anybody interested in learning more about Adobe's great tool. We feature educational videos, which will help you master Adobe Flash and help you get to know all of its features. We at "Flash Video Training Source" believe that video training and video... more

Why don't you follow us on Twitter and get the latest video tutorials twitted to your account. Just click on the floating twitter bar to your right!

Go Back In Time
May 2012
M T W T F S S
« Apr    
 123456
78910111213
14151617181920
21222324252627
28293031  
Pretty Blank Box
top

Blogroll

  • Development Blog
  • Documentation
  • Plugins
  • Suggest Ideas
  • Support Forum
  • Themes
  • WordPress Planet

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org

Archives

  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • December 2011
  • November 2011
  • October 2011
  • September 2011
  • August 2011
  • July 2011
  • June 2011
  • May 2011
  • April 2011
  • March 2011
  • February 2011
  • January 2011
  • December 2010
  • November 2010
  • October 2010
  • September 2010
  • August 2010
  • July 2010
  • June 2010
  • May 2010
  • April 2010
Powered by WordPress  |  Designed by Elegant Themes  |  Lightning Fast Hosting by Site 5 Hosting