Sunday, May 17, 2009

Tutorial: Simulating inertia in 2D with Flash

I was playing around with ActionScript 3.0, in particular making an object accelerate in 2D to simulate inertia. Below is a partial snippet of code that I ended up using:

public var thrust:Number = 1;
public var decay:Number = .9;
public var speed:Number = 0;
public var xSpeed:Number = 0;
public var ySpeed:Number = 0;
public var maxSpeed:Number = 15;
public var xThrustPercent:Number = 0;
public var yThrustPercent:Number = 0;

public var leftkeyPressed:Boolean = false;
public var rightkeyPressed:Boolean = false;
public var upKeyPressed:Boolean = false;

// Respond to keyboard presses
stage.addEventListener( KeyboardEvent.KEY_DOWN, keyPressHandler );
stage.addEventListener( KeyboardEvent.KEY_UP, keyReleaseHandler );

// Update movement every frame
addEventListener( Event.ENTER_FRAME, enterFrameHandler );

protected function keyPressHandler( event:KeyboardEvent ):void
{
  switch( event.keyCode )
  {
    case Keyboard.LEFT:
      leftKeyPressed = true;
      break;

    case Keyboard.RIGHT:
      rightKeyPressed = true;
      break;

    case Keyboard.UP:
      upKeyPressed = true;
      break;
  }
}

protected function enterFrameHandler( event:Event ):void
{
  if( leftKeyPressed )
  {
    rotation -= 10;
  }
  if( rightKeyPressed )
  {
    rotation += 10;
  }
  if( upKeyPressed )
  {
    // Calculate how much thrust to apply to
    // x and y based on the rotation of the object
    xThrustPercent = Math.sin( rotation * ( Math.PI / 180 ) );
    yThrustPercent = Math.cos( rotation * ( Math.PI / 180 ) );

    // Apply the trust to x and y
    // thus accelerating the object
    xSpeed += thrust * xThrustPercent;
    ySpeed += thrust * yThrustPercent;

    // Maintain speed limit
    speed = Math.sqrt( ( xSpeed * xSpeed ) + (ySpeed * ySpeed ) );
    if( speed > maxSpeed )
    {
      xSpeed *= maxSpeed / speed;
      ySpeed *= maxSpeed / speed;
    }
  } else {
    xSpeed *= decay;
    ySpeed *= decay;
  }

  // Move object based on calculations above if ship is visible
  y -= ySpeed;
  x += xSpeed;
}


Obviously, the keyReleaseHandler (which is not shown) does the opposite of keyPressHandler.
Also, you can add a brake functionality to the down arrow if you wish.

Some interesting maths used:

sin( 2700 ) = -1
sin( 00 ) = 0
sin( 900 ) = 1

cos( 00 ) = 1
cos( 900 ) = 0
cos( 1800 ) = -1


Since rotation specifies the rotation of the object in degrees and ActionScript's trigonometric functions (e.g. sin, cos, etc) use radians, you have to convert between the two.

radians = degress * ( PI / 180 )


Lastly, calculating the diagonal distance is done using this simple formula we all learn in school.

diagonal distance = sqrt( x2 + y2 )

No comments:

Post a Comment