Talking about Tower Defense game, Flash and Game development.
Welcome to the 2nd part of this tutorial. I recommend you to check part 1.
In this tutorial, we will place our first base, and it will start to fire.
Let’s have a look at the objects:
base: it’s the base
bullet: it’s the bullet the base will shoot
cant_build: it’s the area where you can’t build a base
minion: already explained in part 1.
path: already explained in part 1.
range: it’s the firing range of the base
Now, a little actionscript all in the first frame:
base_range = 300;
can_be_placed = false;
placed = false;
attachMovie("path", "path", _root.getNextHighestDepth());
attachMovie("cant_build", "cant_build", _root.getNextHighestDepth());
attachMovie("range", "range", _root.getNextHighestDepth(), {_width:base_range, _height:base_range});
attachMovie("base", "base", _root.getNextHighestDepth());
waypoint_x = new Array(40, 140, 140, 220, 220, 80, 80, 340, 340, 420, 420);
waypoint_y = new Array(140, 140, 60, 60, 240, 240, 320, 320, 100, 100, -20);
delay = 25;
new_monster = 0;
monsters_placed = 0;
onEnterFrame = function () {
if (monsters_placed<25) {
new_monster++;
}
if (new_monster == delay) {
monsters_placed++;
new_monster = 0;
min = attachMovie("minion", "minion"+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:40, _y:-20});
min.point_to_reach = 0;
min.speed = 1;
min.onEnterFrame = function() {
dist_x = waypoint_x[this.point_to_reach]-this._x;
dist_y = waypoint_y[this.point_to_reach]-this._y;
if ((Math.abs(dist_x)+Math.abs(dist_y))<1) {
this.point_to_reach++;
}
angle = Math.atan2(dist_y, dist_x);
this._x = this._x+this.speed*Math.cos(angle);
this._y = this._y+this.speed*Math.sin(angle);
this._rotation = angle/Math.PI*180-90;
};
}
};
base.onEnterFrame = function() {
if (!placed) {
this._x = _root._xmouse;
this._y = _root._ymouse;
_root.range._alpha = 100;
can_be_placed = true;
if (_root.cant_build.hitTest(this._x-this._width/2, this._y-this._height/2, true) or _root.cant_build.hitTest(this._x+this._width/2, this._y+this._height/2, true) or _root.cant_build.hitTest(this._x+this._width/2, this._y-this._height/2, true) or _root.cant_build.hitTest(this._x-this._width/2, this._y+this._height/2, true)) {
_root.range._alpha = 0;
can_be_placed = false;
}
}
};
range.onEnterFrame = function() {
if (!placed) {
this._x = _root._xmouse;
this._y = _root._ymouse;
}
};
onMouseDown = function () {
if (can_be_placed) {
placed = true;
}
};
Line 1: Defining the base range
Line 2: Defining if the base can be placed
Line 3: Defining if the base has been placed
Line 5: Attaching the cant_build
movieclip
Line 6: Attaching the range
movieclip and setting its width and height to match base_range
Line 7: Attaching the base movieclip
Line 36: Function to be executed for the base at every frame
Line 37: If the base is not already placed...
Lines 38-39: Move the base to the mouse pointer
Line 40: Set the transparency of the range to 100 (fully opaque)
Line 41: Updating can_be_placed
to true
Line 42: If a corner of the base is over the cant_build area...
Line 43: Setting the transparency of the range to 0 (fully transparent)
Line 44: Setting can_be_placed
to false
What I've done: I let the player move the base with the mouse. If the base can't be placed, because it's over the walking path, I hide the range to make the player know he is on an area where he can't build.
Line 48: Function to be executed for the range at every frame
Lines 49-52: Same thing of lines 37-39... if the base has not been placed, then move the range with the mouse
Line 54: Function to be executed when the player clicks the mouse
Line 55: If the base can be placed...
Line 56: Then set placed
to true
. Now the base is placed
Look: you can now place your base, but only outside the walking path.
Now, we will make the base fire at the foes
base_range = 300;
can_be_placed = false;
placed = false;
firing = false;
attachMovie("path", "path", _root.getNextHighestDepth());
attachMovie("cant_build", "cant_build", _root.getNextHighestDepth());
attachMovie("range", "range", _root.getNextHighestDepth(), {_width:base_range, _height:base_range});
attachMovie("base", "base", _root.getNextHighestDepth());
waypoint_x = new Array(40, 140, 140, 220, 220, 80, 80, 340, 340, 420, 420);
waypoint_y = new Array(140, 140, 60, 60, 240, 240, 320, 320, 100, 100, -20);
delay = 25;
new_monster = 0;
monsters_placed = 0;
onEnterFrame = function () {
if (monsters_placed<25) {
new_monster++;
}
if (new_monster == delay) {
monsters_placed++;
new_monster = 0;
min = attachMovie("minion", "minion"+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:40, _y:-20});
min.point_to_reach = 0;
min.speed = 1;
min.onEnterFrame = function() {
dist_x = waypoint_x[this.point_to_reach]-this._x;
dist_y = waypoint_y[this.point_to_reach]-this._y;
if ((Math.abs(dist_x)+Math.abs(dist_y))<1) {
this.point_to_reach++;
}
angle = Math.atan2(dist_y, dist_x);
this._x = this._x+this.speed*Math.cos(angle);
this._y = this._y+this.speed*Math.sin(angle);
this._rotation = angle/Math.PI*180-90;
if (bullet.hitTest(this._x, this._y, true)) {
firing = false;
bullet.removeMovieClip();
this.removeMovieClip();
}
if (placed) {
distance_from_turret_x = base._x-this._x;
distance_from_turret_y = base._y-this._y;
if ((Math.sqrt(distance_from_turret_x*distance_from_turret_x+distance_from_turret_y*distance_from_turret_y)400) or (this._x>500)) {
firing = false;
this.removeMovieClip();
}
};
}
}
};
}
};
base.onEnterFrame = function() {
if (!placed) {
this._x = _root._xmouse;
this._y = _root._ymouse;
_root.range._alpha = 100;
can_be_placed = true;
if (_root.cant_build.hitTest(this._x-this._width/2, this._y-this._height/2, true) or _root.cant_build.hitTest(this._x+this._width/2, this._y+this._height/2, true) or _root.cant_build.hitTest(this._x+this._width/2, this._y-this._height/2, true) or _root.cant_build.hitTest(this._x-this._width/2, this._y+this._height/2, true)) {
_root.range._alpha = 0;
can_be_placed = false;
}
}
};
range.onEnterFrame = function() {
if (!placed) {
this._x = _root._xmouse;
this._y = _root._ymouse;
}
};
onMouseDown = function () {
if (can_be_placed) {
placed = true;
}
};
Line 4: Setting the firing variable to false. Now the base is not firing
Line 34: Performing an hit test between the minion and the bullet. At this time in the script we haven't already met the bullet, but anyway at this time I am performing this test
Line 35-37: If the test is positive, then remove the bullet and the minion that was hit (at this time minions do not have energy, so my turret is one shot one kill), then set firing to false.
Lines 40-41: Calculating x and y distance between the bullet and the minion
Line 42: If the distance between the bullet and the minion is less than half the range (in our case the range is the diameter of the circle, so half the range is the radius)
Line 43: Boom! The turret fires!
Line 44: Placing the bullet on stage, in the same position of the turret
Line 45: Setting bullet direction, accordind to its x and y distances from the minion
Line 46: Function to be executed for the bullet at every frame
Lines 47-48: Moving the bullet using trigonometry. If you don't know what is trigonometry, then head to this tutorial
Line 49: Checking if the bullet is flying out of the stage
Lines 50-51: In this case, remove the bullet and set firing
to false
again to let the turret fire once more
And here it is our firing turret. You may need to reload the page to have the minion walking while you will place the turret and start killing them.
The fire rate sucks a lot, and the same thing does turret's AI. But I got all those features in only 81 lines, I am sure I will create the complete game in less than 500 lines.
Not today, anyway. Today, download the source and if you have suggestion... just leave a comment.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.