Many of you have been waiting patiently for this post, and let me say that I have worked many hours to get this where it is today. I wanted to get my code to the point where it was solid enough that I would actually publish something with it, and I believe it is there. Thanks to those who have encouraged me to finish this post, and I look forward to seeing how it is used!
In introduction, let me say a few things about this post: first, I have tried to alter my scope slightly in order to be more accessible to readers who may not have access to a full licensed copy of Flash. So, to help with that and make these lessons more accessible, I have decided to write them in such a way as to be compiled by the Flex SDK, a fully open source framework to allow anyone to build robust Flash applications. I prefer to use the full Flex Developer 3 for development and release, but even without it, you can compile full AS3 or Flex applications using only the SDK from the command line. One other major benefit to doing my development with Flex Builder is the ability to publish my source code for all to view online as well as download.
Obviously, this opens up the accessibility to a much broader range of individuals looking to learn Actionscript 3 or Flex. So, all this to say that the code in this post, while doing practically the same thing as the previous posts (and keeping the majority of the same logic), cleans up a ton of structural issues to lend itself more cleanly towards a completed project. That being said, we are simply focusing on the Tower object itself this time. I will leave it to your imagination and time to read through the rest of the cleaned – and fully documented, I might add – code. I may find time to write some more generalized posts on the Flex framework itself in days to come, but for now, suffice to say that the main file that is compiled as the application (in our case, called “MagicTD.as”) will be instantiated as the main() function and will serve as our entire platform base. You will notice on line 12 of this file all the variables needed to set up our SWF with the desired dimensions, background color and framerate.
So, without further ado, let’s jump right into our Tower class.
The Tower Class
Click on the circles in the top right to build three different types of towers.
Many of you have been waiting for an extended length of time for this post, so I hope it does not disappoint. There are so many things to touch on, I will most likely only scratch the surface of the underlying logic and leave the bulk of the understanding for your reading of the code. There are some very significant issues I do want to touch on and overview, though, mainly because I have restructured the handling of some of the movie clips (or Sprites, as the case may be). First off, you will notice that our MagicTD class (base application) houses and manages all the different MovieClip Objects and Sprites itself. This allows for very precise control of the layering of all our objects. So, be sure to take a moment and familiarize yourself with the structure of the class before you proceed any further, or you may find yourself at a loss.
One other thing of which you may need to be aware is the effect of bubbling in handling events in AS3. I have taken advantage of bubbling controls to set up click event handlers for the individual elements (both Creeps and Towers). If you click anywhere else on the SWF, the general MagicTD::clearSelections() method is used as a failsafe. Go ahead, click on Creeps to see their health, and click on Towers to see their range. You can easily add custom click events or additional functionality than I currently have in there by modifying those handlers within each object.
As we look at the Tower class, you should first familiarize yourself with the member variables and what they will do:
game :MagicTD– A reference to the base game itself. This is what we will use to acquire our targets.timer :Timer– A timer to execute our fire() method based upon the fire rate of this towertype :String– A literal descriptive term for the type of tower created (used to distinguish between base tower objects and children)power :int– The base strength of this tower’s shots (without modifiers)range :int– The range at which this tower can see and shoot at a targetrate :int– The fire rate of this tower (shots per second)level :int– The current tower level (not used in this lesson)is_set :Boolean– Whether or not this tower has been set to the map (not used in this lesson)rangeMC :Sprite– The holder for the range SpritetowerMC :Sprite– The holder for the tower Sprite.
Keep in mind this is just for the base Tower class. Within the constructor, you can see that we set default values for these variables if they are not set by a child constructor first. So, when you look at the code base, you will notice a FireTower and IceTower class that each extend and alter some of the default values for these variables, and that causes the difference in behavior of the tower types: simple as that. Were we to be using animations or images for our bullets, this is also where we would override the bullet creation within each child class.
Now for a quick summary of how our Towers and Bullets are behaving. First, the towers themselves simply are on a timer set to fire x number of times per second. When the timer triggers, we call the base MagicTD::fire() method, passing in this Tower object as the parameter. This is because each tower is then handled identically, and it is up to the getNewBullet() method of the Tower to determine the differences between them. You will see this clearly by examining the fire() method of the base MagicTD class (fired whenever a timer event is triggered within a tower):
public function fire(t :Tower) :void
{
try {
var c :Creep = this.obtainTarget(t.x, t.y, t.getRange());
var b :Bullet = t.getNewBullet(c);
this.bullets.push(b);
this.bulletMC.addChild(b);
} catch (e :Error) {
// Do nothing, since we have no targets in range
}
}
Notice that the Tower is what provides the new bullet object to the main MagicTD application to be added to the bullets array and the bulletMC. This allows each Tower to define not only the details of the Bullet to return but also whether or not to use a child class of the Bullet object, had we created any. For simplicity, we will just use the standard bullet object and just assign the power to it based one the power of the Tower object that creates it.
You will notice that the first thing this method does when we attempt to fire is to calculate whether or not we have any creeps in range. If so, we exit out of our loop on the first match to save resources, but if not, we send back an error to keep the SWF from complaining about an invalid return type. If we find a target, we simply create a bullet and assign it a target (by passing in the creep as you can see). The behavior of our bullets is slightly different than that of many TD games out there: rather than doing a collision detection on every enemy and allowing enemies to “intercept” a bullet from its intended target, I have chosen to make more “smart” bullets like the fireballs used by mages in Protector and its sequel Protector: Reclaiming the Throne. In short, the bullets are assigned a target and, once launched, will proceed after that target until it hits or the target is destroyed.
If you do not like this bullet behavior, feel free to modify the code to your liking, but I tend to like this type of predictable, smart behavior, since it allows for more planned placement of my individual towers. A quick review of the Bullet code will let you easily see exactly how we detect, trace and hit a target with our bullets. Notice, too, that bullets and creeps need to be marked as destroyed so that we can do some garbage collection from time to time, too (look at the cleanup_timer and handler code in the MagicTD class).
So, for the most part, this covers the overview of the Tower class and paves the way for full understanding of extending this class into your own custom Tower types. A cursory glance at the FireTower and IceTower classes should answer any questions you have or issues that may arise with handling child constructor methods and overloading parent methods (such as the draw() method).
I hope that my explanation isn’t too much of an overview that it keeps anyone from getting the full benefit of the code, but if you’re anything like me, you will get a much deeper understanding of it by reading the code rather than my feeble attempt at verbalization. So, with that being said, please feel free to bump me with questions, clarifications, bugs or any other relevant comments. After this lesson, you have all the individual pieces needed to create a full Tower Defense style game. If I can muster the time at some point, I will try to complete my own full game and post it for people to see what I came up with. In the meantime, I have to complete development on it first.
As always, I’m providing the source for you to download and modify for your own application. Here you will be able to view and download the entire source for the application seen in this post:
Tower Defense in AS3 – Lesson 4
Please contact me if you have used this to develop a game or application of your own. I’m very interested to see how this is used!
awsome man
I have been waiting for this and visiting your blog almost every day since i found the making of the TD tutorial series.
Very nice work. Well structured code and classes. I like it alot. Thank you very much.
Great Tutorial’s!
How do i get your source to comple and run. I feel like i’m missing a file from the source post?
Looks awesome…I’ll send you the link to my completed project in the next week or so!
Looking forward to seeing some of the finished products! Keep in mind that I’ve only posted the base of the Tower class(es) here. You’ll still need to work out ways to keep people from overlaying towers on each other and/or the road to keep things happy.
This series is intended to get people thinking in the right direction, not be a solve all for everyone
. I will, however, post the full code that I come up with whenever I have time to complete my own full TD game.
I’ll send the source that i create…maybe it will help a your tutorial…this is an excellent base to build from.
I’m trying to make the xml loader from example 3 work with the code from example 4. having a hard time any sugestions?
Ian
It would be used in much the same way, but in this lesson, we don’t have a trigger to tell our wave to wait to load until after the XML loader has returned. You would need to manually wrap the code that starts the wave in a helper function or something that would give you the handle to call from within your XML loader response. Your question is a tad vague, though. If you can show what you’ve tried, perhaps we can help you work through a good solution.
Great, this is so good!!!
so me and my team used the tutorial’s as a base and expanded/changed lots. were very close to a finished game one problem persists. we cant get tower placement limited to off the path and not on top of other towers. Please help! Thanks a lot for the code jump start. I can send you the code if that will help.
The easiest way I know to do this, since we’re using a grid system for placement is to simply have an array of “occupied” spaces. Any time someone tries to move or place a tower, check it against these coordinates. If the space is already occupied, don’t let the action occur. Otherwise, process the action, and then push that grid point onto the coordinates array… hope that helps!
Below is a link to a tower defense game using this tutorial as a base. Lots of code changes and additions. Thanks so much for the starting blocks.
To read about my experiences making this and other projects check out my blog @ http://ianmottsimple.blogspot.com/
http://www.kongregate.com/games/grakusteam/grakus-tower-defense-v1-1?referrer=grakusteam&sfa=permalink
Thanks for all the help!
P.S. email me and i will send you the code.
This tutorial help me to find out
That’s great and thank you.
hello, nice tutorial.
I´ve been taking a look to the code and there is one function that I cannot understand.
what´s super()?
thanx for all.
is there any possibility to get this code for flash instead flex? Or to change some things to get it going with the normal adobe flash? I don’t know a thing about flex and before i try to change some things myself i just thought… why not ask here?
@Gonzalo Gomez:
i think this could help you: http://ntt.cc/2009/07/26/beginning-actionscript-3-super-this-setter-getter.html
if not, just ask
greetings,
Dominik
p.s. excuse my bad english, i’m german -.-
well… delete my question from the last comment
just got it after 5 Minutes looking over the source… (ok, i hope i got it now, but it works fine atm
)
So, for another guy who would use this in the adobe flash environment…
1. just download the source
2. delete the line
“[SWF(width="560", height="320", frameRate="30", backgroundColor="#ffffff")]” from MagicTD.as
3. make a new as3 fla-file
4. modify => width 560 height 320 frameRate 30, bg white (as it is in the SWF command shown above)
5. go to the actions-panel in the first (key)frame
6. type ” var myGame:MagicTD = new MagicTD(); ”
7. type addChild(myGame);
8. go on to modify, play or other things. i’ll do it now
greetings and much thanx for this tutorial, Dominik
Ok, now i’m trying to modify the code and so on, but there is one main problem: the timer which calls the creeps is very imprecise. Weird as it is, when i (firefox, mac osx) open a new tab, the creeps are coming out much faster for any reason. When i start the swf locally, it’s the same thing. Furthermore, the creeps don’t have the exactly same distances between each other.
I looked around the internet, but I just found some big frameworks and didn’t find a good, as simple as possible solution for this.
If it’s possible, could you give me a hint, or a link, to a constant timer class in as3?
I know, the game would be playable without one, but this bug… it just bugs me. It’s always in my head. Wargh!
Great post man
! I have to make a game for my school that isnt bigger than 520 kb. I can get the script any way I want as long as the looks are original and good. But I have some trouble on changing the graphics to MC’s. If someone could mail me how to do that it would be greatly appreciated
! btw ure awesome
Hey, so I’ve been trying to edit your code (which has been extremely helpful) to make the towers rotate towards the creeps. I tried using the Math.atan2 function with the creep’s position but it doesn’t seem to be rotating properly. Any help would be great.
Without looking at your code, it’s a little tough to debug, but the most common issue with rotation is not providing your values in radians. There are many great tutorials regarding rotational calculation. You could look at my post on “omnidirectional movement” and look at the code where the car rotates for one example. Another would be to look at my post doing a motion study using a pendulum.
Hope these get you moving in the right direction!
Okay I was just wondering would it be easier/better to keep things that handle creep spawning inside the main class, or put it into an entirely different class and have the main class call the other class whenever it wants to spawn creeps?
Great tutorials by the way.
Ideally, all individual logic would be handled by their own classes. Keep in mind the tutorial was written as I was exploring, and I’m not necessarily recommending this as an ideal architecture, just an idea of how to approach it.
Glad the tutorials are a help!
-GH