Talking about Artillery game, Actionscript 2, Flash and Game development.
May 25th update: 2nd part released
October 29th update: modification with a bounce effect developed by Massimo M.
Here we are with the beginning of a new tutorial. We are going to create a flash artillery game. Something like Worms. Or similar.
Well… the first thing we need in an artillery game is…
The crosshair
I created a movieclip linkaged as “crosshair”, then on the first frame of the main scene entered this actionscript:
Mouse.hide();
attachMovie("crosshair", "crosshair", 1);
crosshair.onEnterFrame = function() {
this._x = _xmouse;
this._y = _ymouse;
};
Line 1: Hiding the mouse
Line 2: Attaching the movie “crosshair” instanced as “crosshair” at depth 1
Lines 3-5: Every time the crosshair is in the stage, its position is updated to _xmouse and _ymouse coordinates. This means you will move the crosshair with the mouse.
Looks simple… it will get (much) more complicated.
The second thing we need in an artillery game is…
The tank
The tank is the core of an artillery game. You will love your tank. Of course I love mine.
Of course, every tank has its cannon. A big cannon. Size matters.
I created a new movieclip linkaged as “tank” and inside this movieclip I created another one instanced as “cannon”. Look at the picture to understand how I placed the movieclips.
Then the actionscript is:
Mouse.hide();
attachMovie("crosshair", "crosshair", 1);
attachMovie("tank", "tank", 2, {_x:230, _y:350});
crosshair.onEnterFrame = function() {
this._x = _xmouse;
this._y = _ymouse;
};
tank.onEnterFrame = function() {
mousex = _xmouse-this._x;
mousey = (_ymouse-this._y)*-1;
angle = Math.atan(mousey/mousex)/(Math.PI/180);
if (mousex<0) {
angle += 180;
}
if (mousex>=0 && mousey<0) {
angle += 360;
}
this.cannon._rotation = angle*-1;
};
Line 3: places the cannon on the stage
Lines 9-10 determine the x and y distance between the crosshair and the tank
Lines 11-17 determine the angle with trigonometry. This concept is explained in the tutorial called Create a flash draw game like Line Rider or others - part 3.
Line 18 rotates the cannon according to the angle
Sometimes you may need to limit the cannon angle. It's very simple do it this way:
Mouse.hide();
attachMovie("crosshair", "crosshair", 1);
attachMovie("tank", "tank", 2, {_x:230, _y:350});
crosshair.onEnterFrame = function() {
this._x = _xmouse;
this._y = _ymouse;
};
tank.onEnterFrame = function() {
mousex = _xmouse-this._x;
mousey = (_ymouse-this._y)*-1;
angle = Math.atan(mousey/mousex)/(Math.PI/180);
if (mousex<0) {
angle += 180;
}
if (mousex>=0 && mousey<0) {
angle += 360;
}
if (angle>160) {
angle = 160;
}
if (angle<20) {
angle = 20;
}
this.cannon._rotation = angle*-1;
};
Lines 18-23 limit the cannon angle between 20 and 160 degrees. Limiting the cannon angle may affect gameplay, use it wisely.
Now it's time to determine the firepower. In this game, we are going to determine it by the distance from the crosshair to the cannon.
Mouse.hide();
attachMovie("crosshair", "crosshair", 1);
attachMovie("tank", "tank", 2, {_x:230, _y:350});
crosshair.onEnterFrame = function() {
this._x = _xmouse;
this._y = _ymouse;
};
tank.onEnterFrame = function() {
mousex = _xmouse-this._x;
mousey = (_ymouse-this._y)*-1;
angle = Math.atan(mousey/mousex)/(Math.PI/180);
if (mousex<0) {
angle += 180;
}
if (mousex>=0 && mousey<0) {
angle += 360;
}
if (angle>160) {
angle = 160;
}
if (angle<20) {
angle = 20;
}
firepower = Math.sqrt(mousex*mousex+mousey*mousey);
if (firepower>200) {
firepower = 200;
}
this.cannon._rotation = angle*-1;
};
Lines 24-27 calculate the fire power using the pythagorean theorem (there is no need to publish this example as a .swf because visually it does not change anything).
Now it's time to make our tank do what every tank sould do:
FIRE !!
The first thing to do when you fire a bullet is determine the exit point of the bullet. I mean: the cannon is on a rotating turret, so I have to place the bullet right next to the end of the cannon to give the player the feeling he really fired that bullet.
So I created a new movieclip and linkaged it as "cannonball"
Then I added a new function to the script
Mouse.hide();
attachMovie("crosshair", "crosshair", 1);
attachMovie("tank", "tank", 2, {_x:230, _y:350});
crosshair.onEnterFrame = function() {
this._x = _xmouse;
this._y = _ymouse;
};
tank.onEnterFrame = function() {
mousex = _xmouse-this._x;
mousey = (_ymouse-this._y)*-1;
angle = Math.atan(mousey/mousex)/(Math.PI/180);
if (mousex<0) {
angle += 180;
}
if (mousex>=0 && mousey<0) {
angle += 360;
}
if (angle>160) {
angle = 160;
}
if (angle<20) {
angle = 20;
}
firepower = Math.sqrt(mousex*mousex+mousey*mousey);
if (firepower>200) {
firepower = 200;
}
this.cannon._rotation = angle*-1;
};
function onMouseDown() {
angle = tank.cannon._rotation-1
start_ball_x = tank._x+48*Math.cos(angle*Math.PI/180);
start_ball_y = tank._y+48*Math.sin(angle*Math.PI/180);
attachMovie("cannonball", "cannonball", 3, {_x:start_ball_x, _y:start_ball_y});
}
Line 30: Beginning of the actions to be executed when the player press the fire... pardon, the mouse button.
Lines 32-33: Determining the exit point of the cannonball using with trigonometry. This concept too is explained in the tutorial called Create a flash draw game like Line Rider or others - part 3. The "48" value you can see it given by the cannon lenght (40) plus the ball radius (5) plus 3 "safety pixels" since sine and cosine functions returns non-integer values.
Line 34: Attaching the movieclip with the cannon ball. Notice the "3": it's the depth of the movieclip, and giving a fixed depth assure us to have only one cannon ball on the stage.
FIRE!!! (again)
Now that the cannonball has been released, it's time to make it fly.
Mouse.hide();
attachMovie("crosshair", "crosshair", 1);
attachMovie("tank", "tank", 2, {_x:230, _y:350});
crosshair.onEnterFrame = function() {
this._x = _xmouse;
this._y = _ymouse;
};
tank.onEnterFrame = function() {
mousex = _xmouse-this._x;
mousey = (_ymouse-this._y)*-1;
angle = Math.atan(mousey/mousex)/(Math.PI/180);
if (mousex<0) {
angle += 180;
}
if (mousex>=0 && mousey<0) {
angle += 360;
}
if (angle>160) {
angle = 160;
}
if (angle<20) {
angle = 20;
}
firepower = Math.sqrt(mousex*mousex+mousey*mousey);
if (firepower>200) {
firepower = 200;
}
this.cannon._rotation = angle*-1;
};
function onMouseDown() {
angle = tank.cannon._rotation-1;
start_ball_x = tank._x+48*Math.cos(angle*Math.PI/180);
start_ball_y = tank._y+48*Math.sin(angle*Math.PI/180);
cannonball_fired = attachMovie("cannonball", "cannonball_"+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:start_ball_x, _y:start_ball_y});
cannonball_fired.dirx = Math.cos(angle*Math.PI/180)*firepower;
cannonball_fired.diry = Math.sin(angle*Math.PI/180)*firepower;
cannonball_fired.onEnterFrame = function() {
this._x += this.dirx/50;
this._y += this.diry/50;
};
}
Line 34: This time I want more than one cannonball in the stage, so I call the attachMovie function giving the cannon ball the next highest depth available. I can do this using the getNextHighestDepth() function. The name of the movieclip is also affected by the next highest depth available.
Line 35: The dirx variable is the horizontal vector of the cannonball, according to its firing angle and the firepower.
Line 36: Same thing for diry, the vertical vector
Line 37: Every time the cannonball enters in a frame (every frame)...
Lines 38-39: ... its _x and _y position changes according to dirx and diry. That "50" is simply a divider to make the ball not to go too fast.
What happens to a cannonball once in the air? It starts falling due to...
Gravity
In an arcade game initially gravity is not calculated in a strict physics formula, so we are going to simulate the gravity in this way:
Mouse.hide();
gravity = 2;
attachMovie("crosshair", "crosshair", 1);
attachMovie("tank", "tank", 2, {_x:230, _y:350});
crosshair.onEnterFrame = function() {
this._x = _xmouse;
this._y = _ymouse;
};
tank.onEnterFrame = function() {
mousex = _xmouse-this._x;
mousey = (_ymouse-this._y)*-1;
angle = Math.atan(mousey/mousex)/(Math.PI/180);
if (mousex<0) {
angle += 180;
}
if (mousex>=0 && mousey<0) {
angle += 360;
}
if (angle>160) {
angle = 160;
}
if (angle<20) {
angle = 20;
}
firepower = Math.sqrt(mousex*mousex+mousey*mousey);
if (firepower>200) {
firepower = 200;
}
this.cannon._rotation = angle*-1;
};
function onMouseDown() {
angle = tank.cannon._rotation-1;
start_ball_x = tank._x+48*Math.cos(angle*Math.PI/180);
start_ball_y = tank._y+48*Math.sin(angle*Math.PI/180);
cannonball_fired = attachMovie("cannonball", "cannonball_"+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:start_ball_x, _y:start_ball_y});
cannonball_fired.dirx = Math.cos(angle*Math.PI/180)*firepower;
cannonball_fired.diry = Math.sin(angle*Math.PI/180)*firepower;
cannonball_fired.onEnterFrame = function() {
this.diry += gravity;
this._x += this.dirx/50;
this._y += this.diry/50;
};
}
Line 2: A variable called gravity is set to 2
Line 39: The gravity value is added to the vertical vector at every frame.
Final result is quite reasonable.
At the moment the tut stops here, download all source codes, give me feedback, change a line or two and publish them as your own game on various game portals :)
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.