Tutorials

March 5, 2009

AS3 Character Movement: Asteroids Style 360 Degree Movement

More articles by »
Written by: Par
Tags: , , , , , , , ,
tn

Share on TwitterShare on TumblrSubmit to StumbleUponSave on DeliciousDigg ThisSubmit to reddit

Well if we are going to discuss character movement… one of the most important has got to be 360 movement based on rotation. I don’t know if there’s a special name for it, I’ve heard it called everything from 360 degree movement, rotational movement, directional movement, to asteroid style movement. Anyway you want to look at it, it’s a movement style that dates back to arcade games and is definitely a usable option in today’s flash game industry.  So how hard is making this angle based movement going to be? Not hard at all.

You are reading AS3 Character Movement Read more from this series of articles.

In most tutorials on this site we start with a blank slate or a very limited one and work our way up.  This time, due to the simplicity of this tutorial I’m just going to give you the source code from the start.

Download the the source code here: AS3 Character Movement: Asteroids Style 360 Degree Movement Final Zip Archive

Here’s what our finished tutorial will look like:

Sweet huh? Let’s get started.

Step 1: Examining the Zip Archive

The contents of the zip are simple. Directionmovement.fla and Ship.as.  The fla has two MovieClips, our ship and a shadow MovieClip for our ship.  Our ship MovieClip is linked to com.asgamer.directionalmovement.Ship. (If you don’t understand linkage, you should check out the AS3 Flash Games for Beginners series)

Now, there’s something different about this FLA than most on AS Gamer. There is no document class.  If you look at the stage in the FLA file you’ll notice the ship is already placed.  Because it is already placed on the stage, we don’t have to write a document class to place it. All the code that is linked to our ship will automatically run when the fla is compiled into a swf. Now I wouldn’t make a game this way but for testing and experimenting like we are doing now, it’s perfect.

Next look at our ship MovieClip, you’ll notice it faces towards the right. This is because in flash the 0 rotation starts facing right, 90 faces down, 180 faces left, and 270 faces up (clock-wise). So when we use our geometry functions in Flash (Math.cos, Math.sin, Math.tan2) our results will be based on facing right being the 0 rotation.

Step 2: How we make Rotational Movement.

There’s not a lot to say to preface this step. Just look at the code in Ship.as and I’ll break it down afterwards.

package com.asgamer.directionalmovement
{
 
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.events.Event;
	import com.senocular.utils.KeyObject;
	import flash.ui.Keyboard;
 
	public class Ship extends MovieClip
	{
 
		private var key:KeyObject;
		private var speed:Number = 0.3;
		private var rotateSpeed:Number = 5;
		private var vx:Number = 0;
		private var vy:Number = 0;
		private var friction:Number = 0.95;
 
		public function Ship () : void
		{
			key = new KeyObject(stage);
			addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
		}
 
		public function loop(e:Event) : void
		{
 
			if (key.isDown(Keyboard.UP))
			{
				vy += Math.sin(degreesToRadians(rotation)) * speed;
				vx += Math.cos(degreesToRadians(rotation)) * speed;
			} else {
				vy *= friction;
				vx *= friction;
			}
 
			if (key.isDown(Keyboard.RIGHT))
				rotation += rotateSpeed;
			else if (key.isDown(Keyboard.LEFT))
				rotation -= rotateSpeed;
 
			y += vy;
			x += vx;
 
			if (x > stage.stageWidth)
				x = 0;
			else if (x < 0)
				x = stage.stageWidth;
 
			if (y > stage.stageHeight)
				y = 0;
			else if (y < 0)
				y = stage.stageHeight;
		}
 
		public function degreesToRadians(degrees:Number) : Number
		{
			return degrees * Math.PI / 180;
		}
 
	}
 
}

Okay. Breakdown.

  • imports. The same imports we’ve used at AS Gamer many times before. Nothing special here we just need them so we can access the classes.
  • class vars.
    key:KeyObject –
    instance of Senocular’s KeyObject class that we use for checking Key presses
    speed:Number - the speed our ship increases (when we press UP, as we’ll setup later)
    rotateSpeed:Number – the amount of rotation that occurs (when we press LEFT or RIGHT keys)
    vx and vy – the velocity of our ship in x and y
    friction - causes our ship to gradually stop
  • Constructor Function – in our constructor we setup our key object, which needs to stage passed to it and then we setup and ENTER_FRAME event listener so on every frame we can run the loop function
  • key = new KeyObject(stage); If you’ve kept up with the tutorials on AS Gamer you’ll remember that you can’t fully access the stage in a class outside the document class. In this case we can because our ship is on the stage when the game starts.
  • key.isDown(Keyboard.UP). We simply call isDown in our key class and pass the Keyboard key into the function to see if the key is being pressed. It’s just like AS2.
  • vy += Math.sin(degreesToRadians(rotation)) * speed; – The bread and butter of this script. When UP has been pressed we need to adjust our y velocity based on the direction of our ship. If our rotation is 0 or 180 Math.sin will return 0 so our vy isn’t effected. But if our rotation is 90 or 270 it will return 1 or -1 and therefore fully effected.  We do the same with our vx value (except with cosine) to get our results in x.
  • vy *= friction. If  UP isn’t being pressed we apply friction to our vy and vx.
  • Then we check if RIGHT or LEFT is being pressed and apply rotation if so.
  • y += vy. Let’s apply our velocity.
  • x > stage.stageWidth. This section just checks if x is off the screen and resets the x to the other side. It does the same for y.
  • degreesToRadians. Last we create our degrees to radians function to convert between the two.  Math.sin and Math.cos need a radian value instead of degree to work. So we write this function to do the simple conversion then return us the radian value.

Wow simple huh? Now anytime you move something based on it’s rotation, you know how to do it. If we wanted to make an asteroids game, our ship is almost completely finished. All we’d have to do now is add some asteroids and bullets and we’d be pretty much finished. But this tutorial is about movement… There’s other tutorials on this site that will help you with making the bullets and asteroids.

Alright, that’s all for this tutorial, here’s our SWF once again.

And the final source, AS3 Character Movement: Asteroids Style 360 Degree Movement Final Zip Archive

Similar Posts:


Share on TwitterShare on TumblrSubmit to StumbleUponSave on DeliciousDigg ThisSubmit to reddit


About the Author

Par
Hey! Don't be surprised, I'm a flash developer. While Flash is definitely one of my favorite languages to develop in, most of all I just like making games. If you want to see the games I've developed so far head over to my website, DigitallyBold, in the link below. If you want to know more about what I'm working on now and in the future be sure to follow me on twitter.




22 Comments


  1. we got your script but it doens’t work for me.
    it don’t gave any error’s…
    is it because i use more that 1 frame??
    can you help me?

    thank you


  2. Par

    Niels,

    I just downloaded the script as it is on the website and tested it. Everything works fine. What do you mean you used more than one frame?


  3. niels

    Par,

    We made a own game with it.
    But it dont work than even we dont get any errors with it.
    And we use more frame’s in the flash game.
    instead of one frame for the ship, we do a spaceship in more than 1 frame.


  4. Par

    niels, your best bet is to go sign up in the forums and post your code so we can help you figure it out. It could be that you don’t have your linkage setup correctly on your movieclips though… but I’m not sure.


  5. Soonminna

    FANTASTIC!


  6. Not that I’m totally impressed, but this is a lot more than I expected for when I stumpled upon a link on Digg telling that the info here is awesome. Thanks.


  7. Nice man.

    You can put the gravity too. Its more realistic

    Great tutorial. cheers


  8. Sorry, I’m really new to as3 lol, but what would the best method of going about this be?:

    Making the ship rotate like normal, but moving a larget background MC in the opposite directions again for a large scale map style game?

    would just need an example of the movement snippet for bg mc.


  9. Good starting point, but this lacks any sort of maximum speed, so if you hold down thrust you get going insanely fast really quickly. To make a game out of it you need to have some sort of speed limit, like this:

    // enforce speed limit – find length of vector
    // and scale down to maxSpeed if necessary
    var currentSpeed:Number = Math.sqrt((vx * vx) + (vy * vy));
    if(currentSpeed > maxSpeed){
    vx *= maxSpeed / currentSpeed;
    vy *= maxSpeed / currentSpeed;
    }


  10. jaybdemented

    a easier way to set the max speed.

    private var speed:Number = 10;

    and change
    vy += Math.sin(degreesToRadians(rotation)) * speed;
    vx += Math.cos(degreesToRadians(rotation)) * speed;
    to this
    vy = Math.sin(degreesToRadians(rotation)) * speed;
    vx = Math.cos(degreesToRadians(rotation)) * speed;


  11. Par

    @jaybdemented.
    Yes that will work but it will also completely alter the way the ship moves. The sliding effect will no longer work the same way.


  12. Mc

    Thank you so much for the tutorial, I am very new to AS and is trying to build a asteroid game. You are my life saver to be so kind to post these tutorials.
    I have been trying to add the laser to rotate with the ship as well. Should I add the same code to the laser file as well? Right now the laser just shoot straight up and doesn’t rotate. Please give me some advice. Thank you soo much. thank you.


  13. Mc

    Par..
    Still trying to figure out how to face the laser to where the ship is facing. here is the code I am working on, please point me to the right direction…
    for the laser:
    public class LaserBlue extends MovieClip
    {

    private var stageRef:Stage;
    private var bulletSpeed:Number = 16;
    private var xSpeed:Number;
    private var ySpeed:Number;

    public function LaserBlue (stageRef:Stage, pX:Number, pY:Number, pRotation:Number)
    {
    this.stageRef = stageRef;
    x = pX;
    y = pY;
    ySpeed= Math.sin(pRotation * Math.PI / 180);
    xSpeed= Math.cos(pRotation * Math.PI / 180);
    addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
    }

    private function loop(e:Event) : void
    {
    //move bullet up
    x+= xSpeed;
    y+= ySpeed;

    if (y stage.stageWidth)
    x = 0;
    else if (x stage.stageHeight)
    y = 0;
    else if (y < 0)
    y = stage.stageHeight;
    }

    public function degreesToRadians(degrees:Number) : Number
    {
    return degrees * Math.PI / 180;

    }
    private function fireBullet() : void
    {
    //if canFire is true, fire a bullet
    //set canFire to false and start our timer
    //else do nothing.
    if (canFire)
    {
    stageRef.addChild(new LaserBlue(stageRef, x – 40, y + vy, rotation + vx &&vy));
    canFire = false;
    fireTimer.start();
    }

    }

    //HANDLERS

    private function fireTimerHandler(e:TimerEvent) : void
    {
    //timer ran, we can fire again.
    canFire = true;
    }

    }

    }
    Thank you soo soo much for your help. Thank you


  14. Serax

    Mc :

    I see what you’re doing there, and I’m no expert. But I’ve gotten to work with mine and here’s the relevant parts of my BlueLaser.as :

    public function Laser (stageRef:Stage, x:Number, y:Number, rotation:Number) : void
    {
    this.stageRef = stageRef;
    this.x = x;
    this.y = y;
    this.rotation = rotation;

    addEventListener (Event.ENTER_FRAME, loop, false, 0, true);
    }

    private function loop(e:Event) : void
    {
    this.x += Math.cos(this.rotation*Math.PI/180)*speed;
    this.y += Math.sin(this.rotation*Math.PI/180)*speed;

    if (this.x > stageRef.stageWidth)
    removeSelf();
    if (this.y > stageRef.stageHeight-15)
    removeSelf();
    }


  15. Bradnon Capecci

    Use that to get the player to rotate with the mouse:
    xd = this.x-stage.mouseX;
    yd = this.y-stage.mouseY;
    radAngle = Math.atan2(yd, xd);
    this.rotation = int(radAngle*360/(Math.PI*2)-90);

    Use this for creating the shots:
    var shot:Shot = new Shot(stageRef);
    stageRef.addChild(shot);
    shot.x = this.x;
    shot.y = this.y;
    shot.rotation = this.rotation;

    This for moving them:
    x += shotSpeed*Math.sin(rotation*(Math.PI/180));
    y -= shotSpeed*Math.cos(rotation*(Math.PI/180));


  16. Malcolm

    So I tried this tutorial, and was having the toughest time getting my version to work (Flash CS5 Pro). I kept getting an null object error (stage was set to null). Then I noticed your tutorial file had the Flash Player set to FP 9, not 10. So I changed the player in MY .fla file to use FP9 and it worked.

    I’m wondering if you have any knowledge of some error with regards to accessing stage from the document class in FP10?


  17. luuk

    hey great tutorial

    you should create a section about updating the earlier character movement series to use the 360 degree movement


  18. Slay

    Hi

    I really like this tutorial – And I’m trying to make a simple game with it, but the catch is that I want to build the game with Flashbuilder 4 and not Flash Cs5.
    *******************************************
    Now I have made a “Main class” that will import and Add the class “Player” to the stage.
    The class “Player” is basically a (Ship) that imports a MovieClip from flash with linkage.
    *******************************************
    package
    {
    import flash.display.Sprite;

    import fla10.colosseumGame.Units.Player;

    public class ColosseumGame extends Sprite
    {
    private var _Ship:Player;

    public function ColosseumGame()
    {
    _Ship = new Player();
    addChild(_Ship);
    _Ship.x = 200;
    _Ship.y = 100;

    }
    }
    }

    *******************************************

    package fla10.colosseumGame.Units
    {
    import com.senocular.utils.KeyObject;

    import flash.display.Sprite;
    import flash.events.Event;
    import flash.ui.Keyboard;
    import flash.display.Stage;

    public class Player extends Sprite
    {
    private var _player:Expo_PlayerUnit;

    private var _key:KeyObject;

    private var _speed:Number = 0.3;
    private var _rotateSpeed:Number = 5;
    private var _vx:Number = 0;
    private var _vy:Number = 0;
    private var _friction:Number = 0.95;

    public function Player()
    {
    _player = new Expo_PlayerUnit();
    this.addChild(_player);

    _key = new KeyObject(stage);

    _player.addEventListener(Event.ENTER_FRAME, loop, false, 0, true);

    }

    public function loop(evt:Event):void
    {
    if(_key.isDown(Keyboard.UP))
    {
    _vx += Math.sin(degreesToRadians(rotation)) * _speed;
    _vy += Math.sin(degreesToRadians(rotation)) * _speed;
    }
    else
    {
    _vx *= _friction;
    _vy *= _friction;
    }

    if(_key.isDown(Keyboard.RIGHT))
    rotation += _rotateSpeed;

    else if(_key.isDown(Keyboard.LEFT))
    rotation -= _rotateSpeed;

    x += _vx;
    y += _vy;

    if(x > stage.stageWidth)
    x = 0;
    else if(x stage.stageHeight)
    y = 0;
    else if(y < 0)
    y = stage.stageHeight;
    }

    public function degreesToRadians(degrees:Number):Number
    {
    return degrees * Math.PI / 180;
    }
    }

    }

    *******************************************

    Now I don’t get any errors but nothing appears on the stage…

    Please help me with this.

    Thanks


  19. ken

    hi, when i try to move my object up it move right, my object starting position is facing up the screen.the player is a snow border and he has to avoid trees. my code is below:

    package src

    {

    import flash.display.MovieClip;
    import flash.events.*;
    import flash.utils.Timer;
    import flash.events.TimerEvent;
    import flash.text.TextField;

    public class DocumentClass extends MovieClip
    {
    public var mutiple:Array;
    public var tree:Tree;
    public var gameTimer:Timer;

    // Assign 4 booleans for the 4 arrow keys
    public var keypressUp = false;
    public var keypressDown = false;
    public var keypressLeft = false;
    public var keypressRight = false

    public var speed:Number = 0.3;
    public var rotateSpeed:Number = 5;
    public var vx:Number = 0;
    public var vy:Number = 0;
    public var friction:Number = 0.95;

    public function DocumentClass()

    {
    mutiple = new Array();
    var newTree = new Tree( 100, -15 );
    mutiple.push( newTree );
    addChild( newTree );

    addEventListener(Event.ADDED_TO_STAGE,
    init);
    addEventListener(Event.ENTER_FRAME, loop, false, 0, true);

    gameTimer = new Timer( 25 );
    gameTimer.addEventListener( TimerEvent.TIMER, update );
    gameTimer.start();

    }

    public function init(event:Event):void
    {
    stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
    stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);

    }

    public function onKeyDown(e:KeyboardEvent):void
    {

    if (e.keyCode == 38)
    {
    keypressUp = true;
    }
    else if (e.keyCode == 40)
    {
    keypressDown = true;
    }
    else if (e.keyCode == 37)
    {
    keypressLeft = true;
    }
    else if (e.keyCode == 39)
    {
    keypressRight = true;
    }

    }

    public function onKeyUp(e:KeyboardEvent)
    {

    if (e.keyCode == 38)
    {
    keypressUp = false;
    }
    else if (e.keyCode == 40)
    {
    keypressDown = false;
    }
    else if (e.keyCode == 37)
    {
    keypressLeft = false;
    }
    else if (e.keyCode == 39)
    {
    keypressRight = false;
    }

    }

    public function loop(e:Event) : void
    {

    if (keypressUp)
    {
    vy += Math.sin(degreesToRadians(rotation)) * speed;
    vx += Math.cos(degreesToRadians(rotation)) * speed;

    }
    else
    {
    vy *= friction;
    vx *= friction;
    }

    if (keypressDown)
    {

    }
    if (keypressLeft)
    {
    // rotate the object
    player.rotation -= rotateSpeed;
    }
    if (keypressRight)
    {
    // rotate the object
    player.rotation += rotateSpeed;

    }

    player.y += vy;
    player.x += vx;

    if (player.x > stage.stageWidth)
    player.x = 0;
    else if (player.x stage.stageHeight)
    player.y = 0;
    else if (player.y < 0)
    player.y = stage.stageHeight;

    }

    public function update( timerEvent:TimerEvent ):void
    {
    if ( Math.random() < 0.1 )
    {
    var randomX:Number = Math.random() * 800;
    var newTree = new Tree( randomX, -15 );
    mutiple.push( newTree );
    addChild( newTree );
    }

    for each ( var tree:Tree in mutiple )
    {
    tree.moveDownEverySecond();

    if ( player.hitTestObject( tree ) )
    {
    gameTimer.stop();

    }

    }

    }

    public function degreesToRadians(degrees:Number) : Number
    {
    return degrees * Math.PI / 180;
    }

    }

    }

    any help will be appreciated


  20. very nice, but iam developing game with center charecter and bullets, can anybody advice me where i can get good tutorials

    regards,
    maria suzen.


  21. troy

    looked a while for this thank you!


  22. NOHmdD

    Hey I know this an old article, but it was really helpful for my game: I had been putting the angle calculation in the position sections, not the velocity portion. Thanks a lot!



Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">


Advertisement