Flash Race Car Tutorial: Part 1

This tutorial will teach you the basics of making a keyboard controlled racecar in Flash. You could apply this to a spaceship, a gorilla or whatever else you want to control with your keyboard.

Making a car

I'll leave all of the making the car fun up to you. Design it however you want. Mine is going to be a rectangle. Not very aerodynamic, but it will do the trick. Be sure to set the Actionscript Class name of the car to "Racecar" and check the "Export for Actionscript" box in the Properties menu.

Start your engines

Attention Flash MX 2004 users! Flash Player 8 has a bug that causes it to not catch key releases correctly if more than one key is pressed simultaneously. The problem is fixed in later versions of the player, so while you will see it if you test your movie in Flash MX 2004, web users probably won't encounter the problem.

The first step is to set up the car's controls. To allow keyboard buttons to control the car, we need to create a KeyListener object. The KeyListener catches key press and release events similar to the way Flash Button object catches the mouse press and release events. When a key is pressed or released the KeyListener will see that event and show us what key the action happened on. We will program the listener to only pay attention to the arrow keys and call the appropriate function on our car when one is pressed or released.

We are setting up the KeyListener to alert us when the control keys are pressed and when they are released. For instance, when the UP arrow key is pressed, the car will accelerate until it is release. By listening for both the Press action and the Release action we will be able to control the car. I won't bore you too much with all of the details of how the KeyListener works. Instead I'll throw you the code and let you see it yourself.

When I'm debugging KeyListeners, I usually put trace statements in my code to make sure the right functions are linked to the right keys. Add trace statements when you are first writing up the code to save yourself a lot of headaches.

// Create key listener
var keyListener:Object = new Object();
keyListener.onKeyDown = function () {
  switch ( Key.getCode() ) {
	case Key.UP:
		_root.mainCar.ForwardOn();
		break;
	case Key.DOWN:
		_root.mainCar.ReverseOn();
		break;
	case Key.RIGHT:
		_root.mainCar.RightTurnOn();
		break;
	case Key.LEFT:
		_root.mainCar.LeftTurnOn();
		break;
  }
}
keyListener.onKeyUp = function () {
  switch ( Key.getCode() ) {
	case Key.UP:
		_root.mainCar.ForwardOff();
		break;
	case Key.DOWN:
		_root.mainCar.ReverseOff();
		break;
	case Key.RIGHT:
		_root.mainCar.RightTurnOff();
		break;
	case Key.LEFT:
		_root.mainCar.LeftTurnOff();
		break;
  }
}
Key.addListener(keyListener);

Let's burn some rubber

Now that we have a car and some controls, let's get that car moving!

To run everything, we will be writing (or copying) the Racecar Class. Everything the car does will be controlled by this class.

To start out, I'm going to just throw a bunch of code at you. This code sets up the Racecar class as an extension of the MovieClip class. All we are doing here is setting a bunch of variables to be used later and defining the functions we used in the KeyListener earlier.

class Racecar extends MovieClip {
	
	private static var MASS_CONST:Number = 10;
	private static var MIN_SPIN:Number   = 1;
	private static var MAX_TORQUE:Number = 1;
	
	private var maxaccel:Number;      // px. per frame. squared
	private var drag:Number;          // ratio
	private var turnRadius:Number;    // px
	
	private var _turn:Number;         // 1, 0, -1
	private var _accel:Number;        // 1, 0, -1
	private var vel:flash.geom.Point; // px. per frame
	private var heading:Number;       // radians
	private var spin:Number;          // radians per frame
	
	// Initialize all the car variables
	function Racecar() {
		// car characteristics
		this.maxaccel   = 1;
		this.turnRadius = 100;
		this.drag       = 0.05;
		
		// state info
		this.vel = new flash.geom.Point(0, 0);
		this.heading = 0;
		this.spin    = 0;
		this._accel  = 0;
		this._turn   = 0;
		
		this.onEnterFrame = Update;
	}
	
	// Updates car state
	private function Update() {
		// *** We'll discuss this function later
	}
	
	/// - - - - - - - - - - - - - - ///
	///    CAR CONTROL FUNCTIONS    ///
	/// - - - - - - - - - - - - - - ///
	
	// Forward and reverse
	public function ForwardOn() {
		this._accel = 1;
	}
	public function ForwardOff() {
		this._accel = 0;
	}
	public function ReverseOn() {
		this._accel = -1;
	}
	public function ReverseOff() {
		this._accel = 0;
	}
	
	// Left and right turn
	public function RightTurnOn() {
		this._turn = 1;
	}
	public function RightTurnOff() {
		this._turn = 0;
	}
	public function LeftTurnOn() {
		this._turn = -1;
	}
	public function LeftTurnOff() {
		this._turn = 0;
	}
	
}

As you can see, the control functions are pretty simple. They just set the _accel and _turn variables. Rather than bore you with the details of this chunk of code, I wanted to jump straight into the most important part, the Update function. If there is anything here that is confusing to you, or that you'd like explained, feel free to post a comment or send me an email. Hopefully it will all make sense once you see the full code. Each part of the Update function will be explained in detail. Hopefully I don't bore you to death.

The first step is to get the car's heading in radians. All of the Math functions in Flash use radians, but the _rotation property is in degrees.

// get the heading
this.heading = Math.PI / 180 * this._rotation;

The next thing we'll do is update the car's velocity. First, I apply drag to the car. If the car is not accelerating it will slowly come to a stop. The larger the value of drag, the faster the car loses speed. It only takes a little drag to slow the car down, so don't set that value too high.

Also, if the car is accelerating, we increase the velocity in the direction it is pointing. The sin and cos of the car's heading calculates how much of the acceleration should be applied to the x and y direction. The _accel is set by the car control functions and determines whether we are accelerating forward or reverse. The maxaccel variable is how fast the car accelerates. Again, a small value goes a long way here. Set this too high and your car will shoot off the screen. The most important thing is to get your + and - signs right. Otherwise the car will have some interesting behavior.

// Add drag
this.vel.x *= (1 - this.drag);
this.vel.y *= (1 - this.drag);
	
// Add acceleration
this.vel.x += Math.sin( this.heading ) * this._accel * this.maxaccel;
this.vel.y -= Math.cos( this.heading ) * this._accel * this.maxaccel;

The trickiest part of this code is getting the car to turn. A car turns based on how fast it is moving. If it isn't moving at all, it isn't going to turn. The faster you go, the faster it turns. We'll have to calculate how fast the car turns based on how fast it is moving.

Real cars can turn at varying rates depending on how much you crank the steering wheel. To simplify things, this car will only turn at a fixed rate. We "turn" the car by changing its rotation. Based on the speed of the car and the direction it is turning, we'll rotate it. Here is the code that does it. Notice the turnRadius variable. The smaller this number is, the sharper the turn the car will make.

		
var velMag:Number = Math.sqrt(this.vel.x * this.vel.x + this.vel.y * this.vel.y);
this.spin  = velMag / this.turnRadius * this._turn;
var newHeading:Number       = this.heading + this.spin;

Just pointing the car in the right direction isn't enough, though. We also have to change it's velocity to match. I've added an additional feature that allows the car to spin-out if it is turning too fast.

First we calculate how much the velocity will change to get the car moving in the direction it is pointed. I'm calling this value torque. Next we check the magnitude of this torque against a maximum value. If it is greater than the maximum torque allowed, we limit it. This results in the car spinning out. And finally we modify the velocity by the torque.

If you don't want your car to spin out, simply remove the code in the if statement or set MAX_TORQUE very high.

// calculate torque (turning the car changes the direction it travels)
var torque:flash.geom.Point = new flash.geom.Point(0,0);
torque.x =  Math.sin(newHeading) * velMag - this.vel.x;
torque.y = -Math.cos(newHeading) * velMag - this.vel.y;
var torqueMag = Math.sqrt(Math.pow(torque.x,2) + Math.pow(torque.y,2));

// limit torque, so the car will "spin out" if turning too fast
if (torqueMag > MAX_TORQUE) {
	torque.x = MAX_TORQUE * torque.x / torqueMag;
	torque.y = MAX_TORQUE * torque.y / torqueMag;
}

// apply torque to velocity
this.vel.x += torque.x;
this.vel.y += torque.y;

And finally we update the car's position and heading. Not much here, we just set the _x, _y, and _rotation values based on the calculations above.

// update position and heading
this._x       += this.vel.x;
this._y       += this.vel.y;
this.heading   = newHeading;
this._rotation = this.heading * 180 / Math.PI;

And there you have it! A keyboard controlled car of your very own. It might not be as cool as that remote control car that the neighbor has, but this one never runs out of batteries.

Keyboard Controlled Racecar

The Flash plugin is required to view this example.

Feel free to download the full project and play around with the Actionscript files. The best way to learn this stuff is to jump in and experiment, so go for it. I hope you found this tutorial helpful. Any feedback you have on this or any of my other tutorials is welcome. Thanks for stopping by!

This entry was posted in actionscript, Flash, Tutorials and tagged , , , , , , , . Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.miled.net/walid Waloche

    Hi,

    I found your tutorial great! Exactly the help i needed! Thanks for taking the time to do it!

    W

  • http://orangeSPLoTCH.com mattc

    Glad to hear you liked it. Feel free to drop by any time.

    I hope to be building on this tutorial sometime soon.

  • Tim

    Hey, any ideas on applying the torque to reverse? your current source code refuses to even reverse if the torque is applied.

  • deerinaheadlite

    it would be cool if u made it leave skid marks if u turned too fast

  • http://www.onlinegamescar.com Games Car

    What Kinda of Car do you drive?

  • George

    Hi

    Thanks for this great tutorial!!!
    I would like some help with artificial intelligence for cars (for a game).
    Do you have any ideas?

    Thanks in advance!

  • Martin MB

    hi , how make reverse move car?

    • http://orangesplotch.com Matt Carpenter

      That’s a good question and unfortunately I don’t have a quick answer. Way back when I wrote this tutorial I was in the process of putting together a follow-on tutorial to explain it, but it hasn’t happened yet.