In this article, we’ll be using classic flash techniques to create an asteroids ship and move it around on screen using the keys.
This is a quick way to create simpler games, or for any game where you don’t need complex control of the rendering order of your objects.
Note:
Blitting (which is covered in the other asteroids tutorials) is the technique I normally use when creating a game, since it resembles the same way you would create a game in C++ or Java using DirectX or OpenGL, and gives you much better control of the order of objects rendered on screen.
But for simpler games, or ones where you don’t have to group simmilar objects to render in a certain order, using the built-in display list can be much faster.
Creating the project in FlashDevelop and Setting up Main.as
The first thing you need to do is open FlashDevelop, Project->New Project->AS3 Project, and give it a name.
Next, go to Project->Properties and change the dimensions to ‘640×480’, and the Background color to #000000 (black) and click ‘Ok’.
We’ll want to setup the Main class to be able to create and update the game:
Main.as
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite
{
private var game:Game;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
//create the game object passing in the swf width and height
game = new Game(stage);
//Create the main game loop
addEventListener(Event.ENTER_FRAME, game.Update);
}
}
}
Line 8 (game): The main game object that will handle all of our game related tasks.
Line 22: Create the new game object, passing it the stage object, which is needed to add any images to the screen, and handle keyboard/ mouse input.
Line 25 : Add a listener so that every frame (ENTER_FRAME) the update function of our game object will be called.
Creating the Game and Ship Class
Next, we’ll need to create the ‘Game’ class, so right click on the ‘src’ folder on the right hand side, select ‘Add->New Class’, and under ‘name’ enter ‘Game’ and click ‘Ok’.
Now we’ll want to create the ship class. First, right click on the ‘src’ folder, and go to ‘Add->New Folder’ And name it ‘Entities’.
Right click on the ‘Entities’ folder, and click on ‘Add->New Class’. Name it ‘Ship’, click on ‘Browse’ next to BaseClass, and start typing in ‘MovieClip’ and Select ‘Flash.display.MovieClip’ and click ‘Ok’. Check the box that labeled ‘ Generate constructor matching base class’, and click ‘Ok’.
Now add the following code:
Ship.as
package Entities
{
import flash.display.MovieClip;
import flash.geom.Point;
public class Ship extends MovieClip
{
private var speed:Point;
private var speed_multi:Number = .5;
private var friction:Number = .95;
public var thrust:int;
public var rotation_amount:int;
public function Ship(x:int, y:int)
{
super();
this.x = x;
this.y = y;
var width:int = 10;
var height:int = 20;
//Create an internal movieclip to change the rotational point from the top left to the center
var internal_mc:MovieClip = new MovieClip();
internal_mc.graphics.lineStyle(.1, 0xFFFFFF);
internal_mc.graphics.moveTo(0, height);
internal_mc.graphics.lineTo(width / 2, 0);
internal_mc.graphics.lineTo(width, height);
//draw the line across
internal_mc.graphics.moveTo((7*height/8 -height)/(-height/(width/2)), 7*height/8 );
internal_mc.graphics.lineTo((7 * height / 8 -height) / (height / (width / 2)) + width, 7 * height / 8);
//offset the internal drawing so the center is around the top left corner
internal_mc.x = -width / 2;
internal_mc.y = -height / 2;
this.addChild(internal_mc);
speed = new Point(0, 0);
thrust = 0;
rotation_amount = 0;
}
public function Update():void
{
x += speed.x;
y += speed.y;
speed.x *= friction;
speed.y *= friction;
if (thrust != 0)
Thrust();
if (rotation_amount != 0)
rotation += rotation_amount;
}
public function Thrust():void
{
var angle_rad:Number = rotation * Math.PI / 180;
if (thrust == 1)
{
speed.x += Math.cos(angle_rad - Math.PI/2) * speed_multi;
speed.y += Math.sin(angle_rad - Math.PI/2) * speed_multi;
}
else
{
speed.x += Math.cos(angle_rad - Math.PI/2) * (-speed_multi);
speed.y += Math.sin(angle_rad - Math.PI/2) * (-speed_multi);
}
}
}
}
Line 8 (speed): An X and Y value to store the current speed of the ship in both directions.
Line 9 (speed_multi): How fast we will make the ship move.
Line 10 (friction): How much we’ll slow down the ship each update to bring it to a stop.
Line 11 (thrust): For storing whether the ship should move forward/backward (0 when no keys are down, 1 when ‘Up’ is pressed, -1 when ‘Down’ is pressed).
Line 12 (rotation_amount): For storing whether the ship should rotate (0 for no, 15 to rotate it 15 degrees CW, -15 for CCW).
Line 23: Normally a object is setup with its rotation point in the top left hand corner, but we want the ship to rotate around the center. We can either do a matrix transformation (look at the other asteroids tutorial for more information), or we can simply add a ‘dummy’ movieclip, set it at the offset we want (negative half height and width), and we can rotate its parent, which will rotate it about its center.
Line 36: We add the dummy object with the ship drawing on it to the ship objects display list.
Line 42 (Update function): In here, we add any speed to the ship x and y position.
Next, we bring the speed is the x and y direction down by multiplying by our friction amount (95% of the last speed each time).
After that, if our thrust variable is not 0, we call the thrust function.
Lastly, we check if there is any rotation that needs to be done, and add that amount to the ships current rotation amount.
Line 55 (Thrust function): We first convert the rotation amount from degrees to radians, to be able to use Math.cos and sin.
Next, if the thrust is equal to 1, we’ll add the x portion of the max speed at the current angle of the ship to the speed, and the same for the y direction.
Now that we have the ship class complete, we’ll create and handle it from our game class:
Game.as
package
{
import Entities.Ship;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
import flash.events.KeyboardEvent;
public class Game
{
public var stage:Stage;
public var ship:Ship;
private const LEFT:int = 37;
private const UP:int = 38;
private const RIGHT:int = 39;
private const SPACE:int = 32;
private const DOWN:int = 40;
public function Game(stage:Stage)
{
this.stage = stage;
trace("Game created");
//create the ship
ship = new Ship(stage.stageWidth / 2 - 5, stage.stageHeight / 2 - 10);
stage.addChild(ship);
//now for input
stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, KeyUp);
}
public function Update(e:Event):void
{
ship.Update();
}
public function KeyDown(e:KeyboardEvent):void
{
if(e.keyCode==RIGHT)
ship.rotation_amount = 15;
if(e.keyCode==LEFT)
ship.rotation_amount = -15;
if(e.keyCode==UP)
ship.thrust = 1;
if(e.keyCode==DOWN)
ship.thrust = -1;
}
public function KeyUp(e:KeyboardEvent):void
{
if(e.keyCode==RIGHT||e.keyCode==LEFT)
ship.rotation_amount = 0;
if(e.keyCode==UP||e.keyCode==DOWN)
ship.thrust = 0;
}
}
}
Line 13 (stage): The main/root object in actionscript is the stage.
It is needed to handle adding any objects to display on screen, and the keyboard and mouse input. So it makes sense that we will pass it to our game object, and make it available for it to use whenever it needs it.
Line 14 (ship): Our ship object, based on the ‘MovieClass’ type.
Line 16-20: We define the keys we’ll need to use for the game based on their keycode, so we can refer to them by name instead of needing to remember their associated number. You can find out the number for any key by using “trace(e.keyCode);” in either of the functions ‘KeyUp’ or ‘KeyDown’ below.
Line 22: We pass in the stage object in our constructor to be able to use it.
Line 28: Create the ship.
Line 29: Add the ship to the stages display list, so that it will be visible on screen.
Line 32-33: Add the event listeners tot he stage for when a key has been pressed down, or released
Line 35: (Update) Called from ‘Main.as’ on every frame, which will be the place where we update all our game objects.
Line 39: (KeyDown) Called whenever a key has been pressed down (once). In here we check to see which key has been pressed, and set the rotation amount if the right or left key has been pressed, or set the thrust direction if the up or down key has been pressed.
Line 50: (KeyUp) Called whenever a key has been released. If the left or right key has been released, we’ll set the rotation amount to 0, to stop rotating. If the up or down key has been released, we’ll stop aplying thrust to the ship, so that it will come to a stop (due to the friction).
When you compile (Ctrl+Enter), you’ll see your ship in the middle of the screen, and you can move it around using the arrow keys.
Tutorial Demo
In the next section, we’ll create the Bullets and Asteroids.
Download the source Code and please leave me any comments or feedback you have.
Very cool, thanks for this mate! It’s hard finding tutorials that are so organized and concise. And the code is up-to-date to boot, no hair-pulling debug sessions for us beginners!
Hi Chris,
Genuinely thanks for the tute, very simple to follow.
I’ve just started learning AS3 today, but come from a java background. I was wondering if there was any specific reason if at all as to why you defined the constants for the keyboard input rather than importing flash.ui.Keyboard class? Is there some hidden benefit or something?
Thanks again
No, I didn’t know about the constants stored in flash.ui.Keyboard when I originally wrote the tutorial, but that would be an easier way to go, instead of having to figure out the key codes through testing them out 😀
Ahh I see. Thanks for the reply man.