- Joined
- Jun 23, 2009
- Messages
- 297
Basic Tower Defense Tutorial
By Craphter, for The Hive Workshop
Welcome to my Tower Defense tutorial. Here, you will learn how to make a basic TD map from scratch, but, be warned, I start off talking as you already have some basic knowledge. I'll assume it is NOT your first map, since it's not a great idea to start off making a TD.
First off, open up your World Editor, start a new map, I chose these settings, you may choose whichever suit you most:
Whichever terrain you make, it's important that the path where the creeps will move, is an unbuildable terrain. Also, it is quite important that, for now, you make a design that has the features my designs have, because I will be explaining around these features. I'm talking about a single line, and defined start and finish regions.
Once you've layed out a basic terrain (all we'll need for now), well start with the "under the hood" part. First, delete the category that comes by default in the triggers. First, we'll need to set a few variables. Nine to be precise, one optional:
I'll go explaining why we need these variables as we use them, for now, you just need to have all of these, and their exact type. (There is one array, its size is the maximum number of players).
Now, we'll need some regions. This depends on how large your map is, how many turns there are, and how many players will there be. I chose 4 players to keep it simple. You'll need: one region per player in which they'll spawn, one region per turn in the creep's spawn, one region where the creeps are spawned, and one region where the creeps will head to, and die.
Every player needs a builder which will build the tower, right? So, let's create a unit, then we'll detect which players are online, and give them a builder. Open the Object Editor, and copy&paste a human peasant. Start by deleting harvest and call to arms from its abilities, but don't delete repair; it's also a good idea to add "invulnerable (neutral)" to its normal abilities. If you like, you may change the scaling value to a lower or higher number. Then, under "Combat - Attacks enabled", change it to "None". Change "Movement - Movement Speed" to somewhat around 500, and "food cost" to 0. Now, the important part, under "Tech Tree - Structures BUilt", delete ALL the upgrades. Now, change "text - name" to something like "builder", or whichever name you like. That would be all with the Object Editor for now.
Open up the Trigger Editor. I'll be using 3 main categories: general, movement, and waves; but since categories don't really matter, you may use whichever you like. And copy this trigger:
-
Start
-
Events
- Time - Elapsed game time is 0.20 seconds
- Conditions
-
Actions
- Visibility - Disable fog of war
- Visibility - Disable black mask
- Leaderboard - Create a leaderboard for (All players) titled Example TD
- Set Leaderboard = (Last created leaderboard)
- Set TempRegion[1] = RedSpawn <gen>
- Set TempRegion[2] = BlueSpawn <gen>
- Set TempRegion[3] = TealSpawn <gen>
- Set TempRegion[4] = PurpleSpawn <gen>
- Leaderboard - Add Player 12 (Brown) to Leaderboard with label Creeps alive and value AliveCreeps
- Leaderboard - Add Player 5 (Yellow) to Leaderboard with label Lifes left and value LivesLeft
-
For each (Integer A) from 1 to 4, do (Actions)
-
Loop - Actions
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
- ((Player((Integer A))) slot status) Equal to Is playing
-
Then - Actions
- Set TempPoint = (Center of TempRegion[(Integer A)])
- Unit - Create 1 Builder for (Player((Integer A))) at TempPoint facing Default building facing degrees
- Selection - Select (Last created unit) for (Player((Integer A)))
- Custom script: call RemoveLocation( udg_TempPoint)
- Leaderboard - Add (Player((Integer A))) to Leaderboard with label (Name of (Player((Integer A)))) and value PlayerKills[(Integer A)]
- Player - Set (Player((Integer A))) Current gold to 50
- Else - Actions
-
If - Conditions
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
Loop - Actions
- Wait 5.00 seconds
- Game - Display to (All players) the text: First wave in |c00F...
- Custom script: call DestroyTrigger(GetTriggeringTrigger())
-
Events
"Wait whaat? What's all thatf?"
Well, the complicated stuff is called "preventing memory leaks". What are memory leaks, well, in a nutshell, they're little bits of RAM which Warcraft uses to store a lot of different things, like locations, unit groups, unit types, and a LOT more things which I won't cover because it's a tutorial about mapmaking, but, if you wish to know more about memory leaks (Which I highly encourage) read this excellent post. For now, I'll teach you how to prevent them, and that means, storing the location in which the player's builder will be created, in a variable, so after we've used them, we can destroy them, otherwise, the map will be quite laggy. So, what does this trigger do? I'll break it step by step.
The event is quite simple, after 0.20 seconds, this trigger starts running. The first two actions are so that the whole map is visible to everyone (there's no point in hiding anything in a TD), then, we create a leaderboard and store it in a variable, which I'll talk more about later, then, we store 4 regions, 1 for each player (change it acording to the number of players in your map), so that we can use the loop, otherwise it wouldn't work, and, finally, we arrive to the loop. The loop is a for function, present in a LOT of programming languages, and Jass (or GUI) is no exception. What it does, basically, is to run everything in the loop as many times as the user says so, in this case, it says "from 1 to 4", so it will run 4 times. Each time it runs, the variable A increases in 1 number, starting from 1, up to 4. So, all we're doing, is repeating those actions 4 times, for each player. Simple enough, instead of making those actions 4 times, we just put them 1 time, and make the loop execute them 4 times. Then, we wait 5 seconds, just so that the players is overwhelmed right at the beginning, and we warn them that in 10 seconds the first wave will appear.
The last action simply destroys this trigger. Why? Well, because we won't need it anymore. Quoting Ralle: "it is said that destroying triggers after you no longer need them can be quite effective performance-wise, especially with long initialization triggers that run once and are then not used again." (just to clarify, this trigger's leaks are quite small indeed, but, I use the opportunity to introduce new mapmakers to memory leaks. Yes, it's not the best introduction, but now they have a basic concept).
Now, all players have a builder, we need the enemies to kill.
Create a new trigger, with only these actions:
-
Wave Spawner
- Events
- Conditions
-
Actions
- Set TempPoint = (Center of Creep Spawn <gen>)
- Unit - Create CreepsBorn UnitType for Player 12 (Brown) at TempPoint facing Default building facing degrees
- Custom script: call RemoveLocation(udg_TempPoint)
"But Craphter, it has no events, no conditions and only three miserable action, do we REALLY need a separate trigger for this one action?"
No, not really. We seriously don't need a whole trigger for these three actions. But, this is because we only have 1 creep spawn. What if we had 8 creep spawns? The famous "Green Circle TD" has 8 spawns, thus, each time the map spawned a creep, it'd need those three actions times 8, in each wave trigger. For this map, it's almost useless, but, it's a good thing to start making things the right way, right from the start. Maybe the next TD you make does have several spawn points, and it's better that you were taught this way.
If you still don't understand the trigger, do not worry, when we're finished, you will.
Ok, we have a wave spawner, now we need a wave to spawn:
-
Wave 1
-
Events
- Time - Elapsed game time is 15.00 seconds
- Conditions
-
Actions
- Set CreepsBorn = 15
- Set UnitType = Footman
- Trigger - Run Wave Spawner <gen> (ignoring conditions)
- Custom script: call DestroyTrigger(GetTriggeringTrigger())
-
Events
So, after 15 seconds, we set those two variables, and call wave spawner to spawn the creeps. Of course you'll need to make a trigger for each level you want your TD to have, copy&paste them, and go changing the variables values.
Ok, so we have the creeps, spawned, now, we need them to move their skeletons:
-
EnterSpawn
-
Events
- Unit - A unit enters Creep Spawn <gen>
- Conditions
-
Actions
- Set AliveCreeps = (AliveCreeps + 1)
- Set TempGroup = (Units in Creep Spawn <gen> owned by Player 12 (Brown))
- Set TempPoint = (Center of Turn1 <gen>)
-
Unit Group - Pick every unit in TempGroup and do (Actions)
-
Loop - Actions
- Unit - Order (Picked unit) to Move To TempPoint
-
Loop - Actions
- Custom script: call DestroyGroup(udg_TempGroup)
- Custom script: call RemoveLocation( udg_TempPoint)
-
Events
So, we set the variable TempGroup, because unit groups leak, and the same with TempPoint, then, we order all creeps owned by player 12 to move to the first turn, and we clear the variables.
That is a basic movement trigger, and you'll need one for EVERY turn the creeps need to take.
For turn 1:
-
Turn1
-
Events
- Unit - A unit enters Turn1 <gen>
- Time - Every 60.00 seconds of game time
-
Conditions
- (Owner of (Triggering unit)) Equal to Player 12 (Brown)
-
Actions
- Set TempPoint = (Random point in Turn2 <gen>)
- Unit - Order (Triggering unit) to Move To TempPoint
- Custom script: call RemoveLocation(udg_TempPoint)
-
Events
Now, just copy the trigger Turn 1 and paste it as many times as you have a turn in your map, then, change each region's name, and, voilà, our movement system is completed. You might be wondering why I chose "random point in region" instead of "center of region". It's just a little detail so that all creeps won't try to go to the same point in a region, thus, looking kinda crappy, more artificial/robotic, and they'll probably bump into each other much more.
Now, once you've finished all the turns, make a trigger to lead the creep to it's final destination, the end region, and when they enter it, kill it.
-
End
-
Events
- Unit - A unit enters End <gen>
-
Conditions
- (Owner of (Entering unit)) Equal to Player 12 (Brown)
-
Actions
- Unit - Kill (Entering unit)
- Set AliveCreeps = (AliveCreeps - 1)
- Set LifesLeft = (LifesLeft - 1)
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
- LifesLeft Equal to 0
-
Then - Actions
- Game - Defeat Player 1 (Red) with the message: Defeat!
- Game - Defeat Player 2 (Blue) with the message: Defeat!
- Game - Defeat Player 3 (Teal) with the message: Defeat!
- Game - Defeat Player 4 (Purple) with the message: Defeat!
- Else - Actions
-
If - Conditions
-
Events
Now, we need a leaderboard, so, back to the leaderboard I talked about before. First, we store it in a variable, just to do things the right way. In this map it's not necessary because there's only 1 leaderboard, but, the next time you make a map, you might use 2 or more leaderboards, and you'll have to use variables to let the map know which leaderboard you're talking about.
Now, a kill trigger:
-
Kill
-
Events
- Unit - A unit owned by Player 12 (Brown) Dies
- Conditions
-
Actions
- Set AliveCreeps = (AliveCreeps - 1)
- Leaderboard - Change the value for Player 12 (Brown) in Leaderboard to AliveCreeps
-
For each (Integer A) from 1 to 4, do (Actions)
-
Loop - Actions
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
- (Owner of (Killing unit)) Equal to (Player((Integer A)))
-
Then - Actions
- Set PlayerKills[(Integer A)] = (PlayerKills[(Integer A)] + 1)
- Leaderboard - Change the value for (Player((Integer A))) in Leaderboard to PlayerKills[(Integer A)]
- Else - Actions
-
If - Conditions
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
Loop - Actions
-
Events
What are we doing here?
Simple, we just detect who's the owner of the unit (tower) who killed the unit (creep), and add 1 to the PlayerKills variable. We also subtract 1 from creeps alive, and, of course, update the leaderboard.
Extra features:
1- How to sell a tower?
You'd need to create a trigger, and a new unit.
This unit should be called "Sell", which costs 0 gold, and change the icon game interface to "Items - Gold Coins" or whatever you like. Make all tower train this unit under "Techtree - Units Trained".
Then this trigger:
-
Sell
-
Events
- Unit - A unit Begins training a unit
-
Conditions
- (Unit-type of (Trained unit)) Equal to Sell
-
Actions
- Unit - Remove (Trained unit) from the game
- Player - Add (Point-value of (Triggering unit)) to (Owner of (Triggering unit)) Current gold
- Wait 1.50 seconds
- Unit - Remove (Triggering unit) from the game
-
Events
2- What if a player leaves?
We just add this simple trigger:
-
Leaver
-
Events
- Player - Player 1 (Red) leaves the game
- Player - Player 2 (Blue) leaves the game
- Player - Player 3 (Teal) leaves the game
- Player - Player 4 (Purple) leaves the game
- Conditions
-
Actions
- Game - Display to (All players) the text: ((Name of (Triggering player)) + has left the game.)
- Leaderboard - Change the label for (Triggering player) in Leaderboard to <Left the game>
- Set TempGroup = (Units in (Playable map area) owned by (Triggering player))
-
Unit Group - Pick every unit in TempGroup and do (Actions)
-
Loop - Actions
- Wait 1.00 seconds
- Unit - Remove (Picked unit) from the game
-
Loop - Actions
- Custom script: call DestroyGroup(udg_TempGroup)
-
Events
We just need to edit the player's forces so that all players are allies, and the units... Yeah... Just skip that part Craphter. Lazy ass.
I won't show you for two reasons.
1- You should know how to edit units, if you don't, I already taught you with the builder
2- It's up to you, the mapmaker, to input some creativity and personal mark
Do know that balancing the map is one of the hardest parts of mapmaking (if not the hardest), reaching a point in which it's fun to play, but not too easy.
Tips when making the towers:
- REMEMBER to erase all requirements which come by default; really important, or all towers will be unbuildable.
- Remember to set the build time quite low, I'd say maximum of 10 seconds.[/COLOR]
- Remember to make all tower upgradable to a better tower, more options means there are a variety of ways to play the map, which leads to more fun.
- It's a good idea to make towers invulerable (neutral), EVEN THOUGH your creeps should have no attacks enabled, it's just a bit neater.
- Don't tick "structures" under "Combat - Attack 1/2", in your towers, otherwise, they might attack each other.
- It's a REALLY good idea to make towers compliment each other, say, some towers make a lot of damage to certain creeps, but not so much to others, so players make up strategies, and make them think. Take, for example, Warcraft's attack and defense types, there are several types of armours and several types of attacks, all which compliment each other, it's not a good idea to have a whole army of piercing attack, just like it's a bad idea to have a whole army of Fortified.
- DO WORK a LOT more on the terrain, add doodas, cliffs, water, etc.
- Add a storyline, it adds higher quiality to the map ( for more mapmaking tips, read the General Mapping Section
- Remember to erase all ablities which come by default (for example, in guard tower, blight dispell magic, and magic sentry), same as default descriptions, and... well... mostly anything that comes by default.
- It's a good idea to disable "unit can flee", and turn down to 0 the collision size of the creeps; especially if they're getting stuck (this way they won't collide)
- Last, but not least, play your map a LOT, and I mean A LOT, once it's playable, you should keep playing it and testing it, alone, or with bots, or even more helpful, with friends, the more you play it, the more you'll be a ble to improve the gameplay and map experience. Why? Well simply cause when you play it, you discover glitches, bugs and things that need repair. Also, you come up with ideas much much easier, than when simply developing it.
That is all, I really hope you found this useful, and that you just finished your first tower defense map, or, one of your firsts. Do know that I just gave you the basic tools and knowledge you need for a TD... something like a hammer and a nail, now, it is entirely up to you to make the map actually fun, ask yourself, what makes MY TD different from all the other thousands out there? If you can't come up with at least one convincing argument, you need to keep adding features to your map.
Below, I attached my finished TD which I made while I was writing the tutorial. You are free to download it as a template, or to check out why something in yours doesn't work, etc. etc. You may use it however you want.
If you find anything wrong with the tutorial, or my explanations, or the map, or simply have a suggestion, a better way to do stuff, please do let me know, I'm open for any kind of feedback. Also, if you feel you'd like me to add any kind of feature to the tutorial, including how to do X thing, just tell me, I'll gladly work on it.
Thanks to PurgeandFire111, for the great help and tips he gave me.
And finally, thank you for taking the time to read my whole tutorial.
Craphter
Attachments
Last edited: