Make a tanks clone: Part 1 - The tanks
10/04/2008I'm a big fan of tanks. Previously, I wrote about a tank clone written in ActionScript 2.0. This tutorial will show you how to make tanks using OOP in ActionScript 3.0. Therefore, I am assuming that everyone is using Adobe® Flash® CS3. This is what we will be making today:
Up and Down arrow keys to rotate turret. Space to fire, pgUp and pgDown to adjust power.
Getting Started
To start off with, it is good if we make a new folder somewhere, called TanksClone. We'll stick all our files in here and it will be much more organised. Using Flash, create and save the following four files into the folder TanksClone.
- tanks.fla (make sure it is an ActionScript 3.0 document.
- Main.as
- Tank.as
- Bullet.as
These are the only four files that we will be using today.
Note: To create new .as files, press ctrl+N in Flash, select ActionScript File and press OK.
Setting up the graphics
This would be a good place to continue; setting up the graphics. We know that we will need graphics for at least two things - the Tank and the Bullet. Also, we will need a graphic for the Tanks' turret. This is so that we can rotate the turret seperate to the tank later on. OK, this is how we go about it. Draw your tank in Flash using whatever drawing tools you like. Select the tank and press F8 to convert this symbol to a MovieClip. Enter tank_mc into the Name: field but don't press OK yet. Switch to the advanced mode by pressing the Advanced button. Check the box that says Export For ActionScript. Enter Tank into the Class: field.

Repeat this twice by drawing the bullet and the turret, entering into the Class: field Bullet and Turret respectively.
Note: It is convential to name classes with a capital letter at the start of each word eg. MovieClip. Also, on a side note, it is convential to name variables with a lowercase letter at the start and a capital letter for each word thereafter eg. enemiesHealthBarValue. Although these conventions do not always have to be followed; they just make your code neater.
Here's what I drew for each part that we needed:
Tank
Bullet
Turret
Let's make the Tank class!
Alright folks, here we go. Open up Tank.as. This is the code we will be writing in this file:
-
package {
-
-
import flash.display.MovieClip;
-
import flash.display.Stage;
-
import flash.events.KeyboardEvent;
-
import flash.events.Event;
-
import flash.ui.Keyboard;
-
-
public class Tank extends MovieClip {
-
-
public var theStage:Stage;
-
public var up:Boolean = false, down:Boolean = false;
-
public var pgUp:Boolean,pgDown:Boolean;
-
public var power:Number = 3;
-
public var angle:Number = 0;
-
public var turret:Turret;
-
public var playerName:String;
-
public var health:Number;
-
public var canMove:Boolean;
-
public var alive:Boolean = true;
-
-
public function Tank (n:String,s:Stage) {
-
theStage = s;
-
playerName = n;
-
theStage.addEventListener (KeyboardEvent.KEY_DOWN,keyIsDown);
-
theStage.addEventListener (KeyboardEvent.KEY_UP,keyIsUp);
-
addEventListener (Event.ENTER_FRAME,manageMovement);
-
turret = new Turret();
-
addChild (turret);
-
}
-
public function keyIsDown (e:KeyboardEvent) {
-
if (canMove) {
-
if (e.keyCode == Keyboard.UP) {
-
up = true;
-
}
-
if (e.keyCode == Keyboard.DOWN) {
-
down = true;
-
}
-
if (e.keyCode == 33) {//pgUP
-
pgUp = true;
-
}
-
if (e.keyCode == 34) {//pgDOWN
-
pgDown = true;
-
}if (e.keyCode == Keyboard.SPACE) {
-
fire ();
-
}
-
}
-
}
-
public function keyIsUp (e:KeyboardEvent) {
-
if (canMove) {
-
if (e.keyCode == Keyboard.UP) {
-
up = false;
-
}
-
if (e.keyCode == Keyboard.DOWN) {
-
down = false;
-
}
-
if (e.keyCode == 33) {
-
pgUp = false;
-
}
-
if (e.keyCode == 34) {
-
pgDown = false;
-
}
-
}
-
}
-
public function manageMovement (e:Event) {
-
if (canMove) {
-
if (up) {
-
angle+=.02;
-
}
-
if (down) {
-
angle-=.02;
-
}
-
if (pgUp) {
-
power += .02;
-
}
-
if (pgDown) {
-
power -= .02;
-
}
-
} else {
-
up = false;
-
down = false;
-
}
-
turret.rotation = angle * 180/Math.PI;
-
}
-
public function fire () {
-
var vx:Number = power*Math.cos(angle);
-
var vy:Number = power*Math.sin(angle);
-
var bullet:Bullet = new Bullet(x,y,vx,vy,angle);
-
parent.addChild (bullet);
-
canMove = false;
-
}
-
}
-
}
Explanations:
-
package {
-
-
import flash.display.MovieClip;
-
import flash.display.Stage;
-
import flash.events.KeyboardEvent;
-
import flash.events.Event;
-
import flash.ui.Keyboard;
-
-
public class Tank extends MovieClip {
-
-
public var theStage:Stage;
-
public var up:Boolean = false, down:Boolean = false;
-
public var pgUp:Boolean,pgDown:Boolean;
-
public var power:Number = 3;
-
public var angle:Number = 0;
-
public var turret:Turret;
-
public var playerName:String;
-
public var health:Number;
-
public var canMove:Boolean;
-
public var alive:Boolean = true;
Here we are simply setting up this class; importing all the classes we will need and declaring all of our variables.
-
public function Tank (n:String,s:Stage) {
-
theStage = s;
-
playerName = n;
-
theStage.addEventListener (KeyboardEvent.KEY_DOWN,keyIsDown);
-
theStage.addEventListener (KeyboardEvent.KEY_UP,keyIsUp);
-
addEventListener (Event.ENTER_FRAME,manageMovement);
-
turret = new Turret();
-
addChild (turret);
-
}
This is the constructor function. It is run when we first create our Tank object. The two paremeters we recieve are our tank's name and the stage; we use this to communicate with the main movie. We add three listeners here: KEY_DOWN, KEY_UP and ENTER_FRAME. Instead of writing Event.ENTER_FRAME we could have easily written "enterFrame", but this way is neater and causes less headaches if we have any errors in our code.
In the constructor we also create a turret movie clip and add it as a child. All we need this for is to display where our tank is aiming.
-
public function keyIsDown (e:KeyboardEvent) {
-
if (canMove) {
-
if (e.keyCode == Keyboard.UP) {
-
up = true;
-
}
-
if (e.keyCode == Keyboard.DOWN) {
-
down = true;
-
}
-
if (e.keyCode == 33) {//pgUP
-
pgUp = true;
-
}
-
if (e.keyCode == 34) {//pgDOWN
-
pgDown = true;
-
}if (e.keyCode == Keyboard.SPACE) {
-
fire ();
-
}
-
}
-
}
-
public function keyIsUp (e:KeyboardEvent) {
-
if (canMove) {
-
if (e.keyCode == Keyboard.UP) {
-
up = false;
-
}
-
if (e.keyCode == Keyboard.DOWN) {
-
down = false;
-
}
-
if (e.keyCode == 33) {
-
pgUp = false;
-
}
-
if (e.keyCode == 34) {
-
pgDown = false;
-
}
-
}
-
}
These two functions each listen for an event: keyIsDown() listens for KeyboardEvent.KEY_DOWN and keyIsDown() listens for KeyboardEvent.KEY_UP. These simply change the value of booleans up, down, pgUp and pgDown so that we can either tell if one of those keys are being pressed or not. We then go on, in manageMovement() to adjust power and angle every frame if one of these are down. I like to handle keys this way because it gives a more fluid result.
keyIsDown() also calls the function fire() if the space bar is pressed.
canMove is simply a boolean - It is changed to false after the tank fires and will then be later changed to true after it is this tank's turn again.
-
public function manageMovement (e:Event) {
-
if (canMove) {
-
if (up) {
-
angle+=.02;
-
}
-
if (down) {
-
angle-=.02;
-
}
-
if (pgUp) {
-
power += .02;
-
}
-
if (pgDown) {
-
power -= .02;
-
}
-
} else {
-
up = false;
-
down = false;
-
}
-
turret.rotation = angle * 180/Math.PI;
-
}
Simply adjusts power/angle variables and the turret's rotation.
-
public function fire () {
-
var vx:Number = power*Math.cos(angle);
-
var vy:Number = power*Math.sin(angle);
-
var bullet:Bullet = new Bullet(x,y,vx,vy,angle);
-
parent.addChild (bullet);
-
canMove = false;
-
}
When this function is called the tank fires a bullet using its current angle and power to work out velocities for the bullet. We then add the bullet to our parent MovieClip and set canMove to false (we have now finished our turn.)
The Bullet Class
Open Bullet.as and plug in this code:
-
package {
-
-
import flash.display.Sprite;
-
import flash.display.MovieClip;
-
import flash.display.Stage;
-
import flash.events.Event;
-
-
public class Bullet extends Sprite {
-
-
public var vx:Number = 1;
-
public var vy:Number = 0;
-
public var ay:Number = 0.05;
-
-
public function Bullet (_x:Number,_y:Number,_vx:Number,_vy:Number,_angle:Number) {
-
vx *= _vx;
-
vy =_vy;
-
x = _x;
-
y = _y;
-
rotation = _angle * 180/Math.PI;
-
addEventListener (Event.ENTER_FRAME,manageMovement);
-
}
-
public function manageMovement (e:Event) {
-
//Move the bullet
-
vy += ay;
-
y += vy;
-
x += vx;
-
//Work out its rotation
-
var _angle = Math.atan2(vy,vx);
-
rotation = _angle * 180/Math.PI;
-
if (x <0 || x> 600 || y <0 || y> 400) {
-
dispose ();
-
}
-
}
-
public function dispose () {
-
removeEventListener (Event.ENTER_FRAME,manageMovement);
-
MovieClip(parent).increaseTurn ();
-
parent.removeChild (this);
-
}
-
}
-
}
This code will manage the bullet's when they are on the stage. All we do here is have a listener listening for the "enterFrame" event so that the bullet adjusts its' position and rotation every frame. If the bullet is outside the stage, dispose of the bullet (remove listener and remove it from its' parent.)
The Document Class
Now that we have written the classes for both the tank and bullet, we now have to write a controlling class, which will add the tanks to the stage and manage turns etc.
Open tanks.fla and head towards the Properties panel. In the text box labeled Document class enter "Main" (without the quotations.)
This means that Main.as is linked to this flash document. Whenever we run the .swf, Main.as is instantiated.
Open Main.as
Plug in this code:
-
package {
-
-
import flash.display.MovieClip;
-
import flash.events.KeyboardEvent;
-
import flash.text.TextField;
-
-
public class Main extends MovieClip {
-
-
public var tanks:Array = new Array();
-
public var turn:int = 0;
-
public var displayName:TextField;
-
-
public function Main () {
-
tanks.push (new Tank("Player One",stage));
-
tanks.push (new Tank("Player Two",stage));
-
tanks.push (new Tank("Player Three",stage));
-
for (var i in tanks) {
-
tanks[i].x = Math.random()*580+10;
-
tanks[i].y = 350;
-
addChild (tanks[i]);
-
}
-
tanks[0].canMove = true;
-
-
displayName = new TextField();
-
displayName.selectable = false;
-
addChild (displayName);
-
displayName.text = tanks[0].playerName + "'s turn";
-
}
-
public function increaseTurn () {
-
turn++;
-
if (turn>= tanks.length) {
-
turn = 0;
-
}
-
while (!tanks[turn].alive) {
-
turn++;
-
if (turn>= tanks.length) {
-
turn = 0;
-
}
-
}
-
tanks[turn].canMove = true;
-
displayName.text = tanks[turn].playerName + "'s turn";
-
}
-
}
-
}
When run for the first time, this code adds three tanks (Player one, Player two and Player three) to the array tanks. We then go on to add these three tanks to the stage, at random positions. We then proceed to make our first tank movable by setting canMove to true.
The next part is simply setting up a text box that will let us know whose turn it is.
increaseTurn() does simply that, it increases the number that relates to whose turn it is (bypassing the dead tanks) and makes that tank able to move. The final little bit of this updates the text field with new information about whose turn it is.
Using these classes that we have created today, you should be able to compile the movie and it should run like the one shown above.
If you have had any problems at all, please don't hesitate to leave me a comment and I'll get back to you!
In the next part to this tutorial we will learn how to kill the tanks and we will also create destructible terrain!
Thanks for reading!





No comments yet.