Flash Tutorial Links:
Play Games: HTML5 Tutorials:

How To Make A Tower Defense Game (Part 2)

3 unique towers have become a staple in Tower Defense games - the straight forward, no nonsense shooter tower, the slow tower, and an AOE tower. Learn how to make them all!

Back to How To Make A Tower Defense Game (Part 1).

Step 4 - The Game Loop, Handling User Controls

Finally, let's move on to the Game Loop. As usual, let's see what are the user controls we need to handle.

272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
public function update(evt:Event)
{
    //******************			
    //Handle User Input
    //******************
    if (hitEscape)
    {
        if (currTower)
        {
            //cancel build
            if (currTower is Tower_Fire)
            {
                //refund gold
                currGold += C.TOWER_FIRE_COST;
            }
            else if (currTower is Tower_Ice)
            {
                //refund gold
                currGold += C.TOWER_ICE_COST;
            }
            else if (currTower is Tower_Lightning)
            {
                //refund gold
                currGold += C.TOWER_LIGHTNING_COST;
            }
            mcGameUI.removeChild(currTower);
            currTower = null;
    
            for (var i in placings)
            {
                placings[i].gotoAndStop("off");
            }
        }
    }
    hitEscape = false;
    
    if (currTower != null)
    {
        currTower.x = mouseX;
        currTower.y = mouseY;
    }

The entire chunk of codes from lines 277 to 306 handles what happen when the player hits the escape key. Basically, there is only one use for it, that is, after he clicks on the build tower buttons, he may change his mind. To cancel this current option of tower he selected (and remember currTower visually displays this tower he has currently chosen), he presses the Escape key. The variable hitEscape is set to true by the keyDownHandlers you can find in the GameController when that happens.

Line 279 checks if the player has already clicked on a tower, because if he hadn't, there's really nothing for you to cancel. Then, they next few lines check what kind of a tower the player had clicked previously, basically by comparing the class that currTower is, and then refunds the player this amount of gold.

Lines 297 and 298 removes the currTower from the mcGameUI, and then sets it to null, thereby cancelling the current tower.

Lines 308 to 312 makes the currTower follow the mouse movement, if it exists.

Step 5 - The Game Loop, Handling Game Logic

Finally, we have reached the crux of the game loop. Let's take a look at the spawning of the mobs first.

317
318
319
320
321
322
323
324
//Update the mobs
if ((currWave < maxWave) && (monsters.length == 0))
{
    currWave++;
    
    //spawn the monsters
    spawnWave(currWave);
}

The condition in line 318 checks that the currWave is less than maxWave, i.e. there are more waves that need to come before we end the game. currWave starts off as 0, and maxWave is a value we set earlier on. In the tutorial, I set it as 20, but you are free to change this. The second part of the condition checks that there is nothing in the monsters array because we only want the next wave to come when all the monsters in this current wave have been killed.

Line 320 increases the current wave number, and line 323 calls upon spawnWave to unleash the new mobs. Let's just move forward to see what spawnWave does.

434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
...
//Spawning of monsters
private function spawnMonster(xPos, yPos)
{
    var monsterToSpawn = new Monster();
    monsterToSpawn.x = xPos;
    monsterToSpawn.y = yPos;
    monsters.push(monsterToSpawn);
    mcGameStage.addChild(monsterToSpawn);
}
 
private function spawnWave(currWave)
{
    if (currWave == 1)
    {
        spawnMonster(C.MONSTER_START_X, C.MONSTER_START_Y);
    }
    else if (currWave == 2)
    {
        for (var i = 0; i < 2; i++)
        {
            spawnMonster(C.MONSTER_START_X - 40*i, C.MONSTER_START_Y);
        }
    }
    else if (currWave == 3)
    {
        for (var i = 0; i < 4; i++)
        {
            spawnMonster(C.MONSTER_START_X - 40*i, C.MONSTER_START_Y);
        }
    }
    ...

I wouldn't go much into the function spawnMonster. Suffice to know that it creates a single monster of class Monster where you can specify the x and y position of it.

Examine the function spawnWave. The if-else conditions go on until the maxWave, which is 20, but I'll just highlight 3 of them, since they're essentially the same. Remember that spawnWave is a function that is called with 1 parameter, which is the currWave. For the first wave, therefore, we can see that in line 448, only 1 monster is spawned.

For the second wave, lines 452 to 455 uses a for loop to create a total of 3 monsters. This is where you can potentially change the design to suit your needs. In my tutorial, I only have 1 Monster type, hence I used a for loop. If you have a few different monster types, you can create spawnMonster1, spawnMonster2, etc to create different monsters accordingly.

What's interesting in the modification of the x parameter in line 454. Basically, it just means creating the first monster at the x and y position denoted by C.MONSTER_START_X, C.MONSTER_START_Y. The second monster created needs to be a little farther back from the first one, and the third monster a little farther than the second. Line 454 takes care of that. Look at this picture for a clearer idea.

spawn

I expanded the swf so that you can see parts of the hidden stage. You can see that each monster is spaced a little distance apart. That was what line 454 was trying to do.

Now, let's take a look at what is causing the monsters to move.

326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
for (var i=monsters.length - 1; i >= 0; i--)
{
    if (monsters[i].currLife > 0)
    {
        monsters[i].update();
    }
    
    //Check if monster reaches the end of their path
    if (monsters[i].hasReachedDestination())
    {
        monsters[i].gotoAndStop("remove");
        life -= 1;
    }
    
    if (monsters[i].currentLabel == "remove")
    {
        mcGameStage.removeChild(monsters[i]);
        monsters.splice(i,1);
        
        //Award Gold
        currGold += C.MONSTER_GOLD;
    }
}

Line 328 checks that the monster is alive first before allowing it to take action and update. We'll take a look at the monster's update function later.

Line 334 checks if the monster has reached its destination, which is the end of the tower defense map. If so, the monster's frame is told to jump to the label remove. But, when the monster has reached the end of the tower defense map, it means that there is a "leak", hence the player is penalised with a -1 to his life in line 337.

Then line 340 checks for monsters with their timeline head at the "remove" label, and remove them (in lines 342 and 343). Line 346 awards gold to the player EVEN IF the monster has leaked. I did this to better balance the game, so that early leakages do not snowball to the end. If you have time to balance your game otherwise, this line should be removed.

Now, let's look at the Monster.as inside the Game package to see what goes on in the update function.

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public function Monster()
{
    maxLife = C.MONSTER_LIFE;
    currLife = maxLife;
    speed = C.MONSTER_SPEED;
    
    currIndex = 0;
    
    checkPoints = new Array();
    checkPoints.push(new Point(85,140));
    checkPoints.push(new Point(85,320));
    checkPoints.push(new Point(325,320));
    checkPoints.push(new Point(325,200));
    checkPoints.push(new Point(265,200));
    checkPoints.push(new Point(265,80));
    checkPoints.push(new Point(505,80));
    checkPoints.push(new Point(505,380));
    checkPoints.push(new Point(630,380));
}

Let me explain what checkPoints is used for. It is an array that stores the coordinates of the various points in the map where the monster must reach. There is a little bit of manual work here whereby you really need to check the coordinates of the turning points in your map, but once you get it nailed down, it's pretty straightforward. By turning points, I refer to this:

check points

Lines 22 to 30 is basically checking the coordinates of the red circles, and pushing them into the array. The very last point pushed in at line 30 is the final end point where the monster should travel to. Once it reaches that spot, it is considered a leak (player loses 1 life).

The variable currIndex stores where the monster has moved to so far. The monster always travels to the position pointed to by checkpoints[currIndex], so right at the start, the monster will start to move to checkpoints[0], which denotes the position (85,104). We'll examine that in the update function below.

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public function update()
{
    var finalSpeed:Number;
    
    if (slowTimer > 0)
    {
        finalSpeed = speed / 2;
        slowTimer--;
    }
    else
        finalSpeed = speed;
        
    if (currIndex < checkPoints.length)
    {
        //move in the direction of the checkpoint
        if (this.x < checkPoints[currIndex].x)
            this.x += Math.min(finalSpeed, Math.abs(this.x - 
                                        checkPoints[currIndex].x));
        else if (this.x > checkPoints[currIndex].x)
            this.x -= Math.min(finalSpeed, Math.abs(this.x - 
                                        checkPoints[currIndex].x));
            
        if (this.y < checkPoints[currIndex].y)
            this.y += Math.min(finalSpeed, Math.abs(this.y - 
                                        checkPoints[currIndex].y));
        else if (this.y > checkPoints[currIndex].y)
            this.y -= Math.min(finalSpeed, Math.abs(this.y - 
                                        checkPoints[currIndex].y));
        
        if ((this.x == checkPoints[currIndex].x) &&
            (this.y == checkPoints[currIndex].y))
        {
            currIndex += 1;
        }
    }
    
    //display
    if (currLife > 0)
                mcLifeBar.width = Math.floor((currLife/maxLife)*
                                                    C.LIFEBAR_MAX_WIDTH);
    else
        mcLifeBar.width = 0;
}

In almost all tower defense games, there is a tower that can slow the monster's speed, usually by half or more. Lines 35 to 43 takes care of this logic. The way I implement it here in this tutorial, whenever the monster should be slowed, this variable slowTimer is given a number. If it takes on a number of 30, it means for 1 second (since 30 fps), it will be slowed. According to line 39, I will slow it from its original speed down to half.

Line 45 checks if the currIndex is lower than the total length of the checkPoints array, meaning that the monster has yet to reached its final checkpoint yet. The subsequent few lines are basically the same, but let me take line 48 to explain. If the x position of the current monster is lesser than the x position of its next checkpoint, in line 49, its x value will be increased by the minimum of either its eventual speed, or the distance between his current position and the checkpoint.

The reason why this is done is to prevent the Monster from ding-donging around the checkpoint. Imagine a case where the speed of the monster is 10 pixels, and it is currently 5 pixels on the left of its checkpoint. Without this logic, it will move 10 pixels and land 5 pixels on the right of its checkpoint. Then it makes a check again and realises it is now on the right, hence it moves 10 pixels to the left. And alas, now it is 5 pixels on the left again. Thus, he will never reach the checkpoint if this holds true.

In line 62, once we ascertain that the monster has reached its checkpoint, the currIndex value is increased by 1, thus prompting the monster to seek out its next checkpoint.

Lines 70 to 74 takes care of the health bar display in each monster. currLife / maxLife gives a percentage of its life left. When multiplied by the width of the life bar, it gives a full health bar when it is at max life, and 0 pixels wide when its health is 0.

Back to GameController.as. Moving on, we move onwards to update the towers. Each of the towers is stored inside this array called towers, so we'll be calling their own individual update function.

350
351
352
353
354
//Update all the towers
for (var i in towers)
{
    towers[i].update();
}

I separated the logic for the three towers into Tower_Fire.as, Tower_Ice.as and Tower_Lightning.as. Actually, we should have used inheritance to simplify and optimise things. But, again, for the sake of easy explanation, I'm going to break them up. Let's examine Tower_Fire since it's the most direct attacking tower.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public function update()
{
    if (isActive)
    {
        var monsters = GameController(root).monsters;
        if (cooldown <= 0)
        {
            for (var j = 0; j < monsters.length; j++)
            {
                var currMonster = monsters[j];
                
                if ((Math.pow((currMonster.x - this.x),2) 
                    + Math.pow((currMonster.y - this.y),2)) < this.range)
                {
                    //spawn new bullet
                    var bulletRotation = (180/Math.PI)*
                                Math.atan2((currMonster.y - this.y), 
                                        (currMonster.x - this.x));
                    var newBullet = new Bullet(currMonster.x,currMonster.y,
                            "fire",currMonster,this.damage,bulletRotation);
                    newBullet.x = this.x;
                    newBullet.y = this.y;
                    
                    GameController(root).bullets.push(newBullet);
                    GameController(root).mcGameStage.addChild(newBullet);
                    
                    this.cooldown = C.TOWER_FIRE_COOLDOWN;
                    
                    break;
                }
            }
        }
        else
        {
            this.cooldown -= 1;
        }
    }
}

There're quite a lot of things here to cover, so let's go over it slowly. Line 28 first checks whether this tower is currently active and acts only if it is. Remember that when you click on the tower building buttons initially, a tower is already created, but its default state is inactive. That's why it doesn't do any shooting as yet.

Once it is placed onto the game stage, its isActive boolean is set to true, and all the logic here will kick in. Each of the tower has a cooldown class variable that stores the amount of time it needs before it shoots again. This is necessary so that we don't see it shooting 30 missiles per second (on a 30fps basis). So line 31 ensures that it is time to act.

It retrieves the monster array from the game controller in line 30 (remember that these arrays have been set to public). The monsters within the array are looped, and lines 37 and 38 is our famous geometrical formula between 2 points. Well ... almost, with an optimisation. You can see that in lines 37 and 38, we take the (square of the x distance) + (square of the y distance) (let me denote this as dist_tower_to_monster) and compare it to the range directly. Our mathematical memory should tell us that distance between two points is the square root of dist_tower_to_monster.

Well, this is an optimisation, like I said. If I want the range of a tower to be 10 pixels, we could take the square root of dist_tower_to_monster and compare it to 10. Or, to optimise it, I can save on the time taken to compute the square root, and compare it directly to the square of 10, which is 100. In my tutorial, I chose the latter, that's why you see the ranges listed in the C.as as being so large.

Moving on, if the monster is within range, the if condition holds true, and we proceed to spawn a new bullet. Line 41 calculates the rotation of the bullet. Yes, I know it's mathsy ... but hey, you can't code games without a firm mathematical background. =) That's one of the reasons why Digipen emphasizes so much on Maths.

Line 44 creates a new bullet, passing in all the necessary parameters, which we'll go into later when we examine the Bullet.as class. Lines 49 and 50 pushes this new bullet into the bullets array which handles them, and adds it onto the game stage so that we can see it.

Line 54 breaks the current loop so that a tower can only fire a bullet at a monster. An easy modification can be done here if you want the tower to target and fire a bullet at all monsters within range. Simply remove the break in line 54.

Line 60 constantly reduces the cooldown of the tower so that it gets ready to fire again.

If you open up Tower_Ice.as and Tower_Lightning.as, you'll realise that the codes are almost identical. Except that you'll find the spawning of bullet in line 45 to reflect "ice" and "lightning" respectively. Again, like I said, this is where you can easily use inheritance to simplify your codes.

Now, we move on to the code for the bullets.

356
357
358
359
360
361
362
363
364
365
366
//Update all the bullets
for (var i=bullets.length - 1; i >= 0; i--)
{				
    bullets[i].update();
    
    if (bullets[i].currentLabel == "remove")
    {
        mcGameStage.removeChild(bullets[i]);
        bullets.splice(i,1);
    }
}

The codes to do the updating of the bullets look very similar, and it's basically looping through the entire bullets array and calling them to update. In line 361, we check if any of the bullets is currently at their "remove" label frame, and if so, they are removed. You would noticed that this is a technique I use frequently to remove things from stage.

Now, we need to examine what goes on in the update function of the bullet. Open up the Bullet.as file.

12
13
14
15
16
17
18
19
20
21
public function Bullet(targetX,targetY,type,targetRef,damage,rotate)
{
    this.targetX = targetX;
    this.targetY = targetY;
    this.gotoAndStop(type);
    this.targetRef = targetRef;
    this.damage = damage;
    this.rotation = rotate;
    this.speed = C.BULLET_SPEED;
}

The constructor for the Bullet looks normal, but examine line 16. Remember that when each of the towers created a bullet, the difference lies in passing in "fire", "ice" or "lightning" mainly. This is where the significance shows. If you open up the Bullet Movieclip in the FLA file, you'll see that it looks like this.

bullet mc

I'm basically trying to reuse the same movieclip for all the bullets. In a more complex environment where you will have lots of animation for each bullet, this style may not work for you. For now, it is ok.

Line 19 is important too in the sense that the bullet is rotated to face the target where it is supposed to reach. This has to be done so that it looks natural, and also to ensure that it moves in the correct direction. As you'll realise later, this rotation is part of the movement logic.

Now, let's take a look at the update function.

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public function update()
{
    this.x += this.speed * Math.cos(Math.PI * this.rotation/180);
    this.y += this.speed * Math.sin(Math.PI * this.rotation/180);
    
    if (this.hitTestPoint(targetX,targetY))
    {
        //if this is a lightning bullet, 
        //it will damage all nearby monsters
        if (this.currentLabel == "lightning")
        {
            var monsters = GameController(root).monsters;
            for (var i = 0; i < monsters.length; i++)
            {
                var currMonster = monsters[i];
                
                if ((Math.pow((currMonster.x - this.x),2) 
                        + Math.pow((currMonster.y - this.y),2)) 
                            < C.LIGHTNING_AOE_RANGE)
                {
                    currMonster.takeDamage(this.damage);
                }
            }
        }
        else if (this.currentLabel == "ice")
        {
            //Add Slow Effect to monster
            this.targetRef.slowDown(C.TOWER_ICE_SLOW_AMOUNT);
            this.targetRef.takeDamage(this.damage);
        }
        else
        {
            this.targetRef.takeDamage(this.damage);
        }
        
        this.gotoAndStop("remove");
    }
}

Line 25 and 26 moves the bullet in the x and y axis based on resolving the x and y component of its speed and rotation. Again, this is pretty mathsy, but recall your trigonometry and it should make sense.

trigo

I hope the picture above jolts back some of your memory from your maths lessons. =)

Line 28 indicates the stop condition for the bullet. It is always intended to move only to a point (where the monster was when it fired). This point is indicated by targetX and targetY. Once the hitTest holds true, it means that it has reached.

The code within the if condition is interesting. We check whether the bullet is a lightning bullet, meaning it fired from the Lightning tower. If so, remember that the lightning tower can actually damage nearby enemies of its target. That's why in lines 34 to 41, you see the code that loops through all the monsters on stage again, and check whether they are in the lightning AOE range. If so, they take damage too.

Line 47 handle the ice bullets, and adds in a freeze effect to the monster that gets hit by it in line 50.

Line 55 is just the straightforward damage for the Fire Tower.

That handles the most difficult-to-understand parts of this code. You'll realise that this way of handling bullet movements is very useful, and can be used for a wide variety of games.

Now, let's carry on with the game logic. Back to your GameController.as.

368
369
370
371
372
373
374
375
376
377
378
379
//Check for end game
if (life <= 0)
{
    gameOver();
    
    //stop all subsequent code in this update to run
    return;
}
else if ((currWave == maxWave) && (monsters.length == 0))
{
    gameWin();
}

Naturally, I placed such frame changing codes towards the end of the game loop. If the player's life is 0 or less, we execute the gameOver() function, which does the removal of event listeners, etc, and most importantly, bring the player to the frames labelled "gameOver".

Otherwise, if the currWave is the same as maxWave and there isn't any more monsters left in the game, then the gameWin() function is called, and the player is brought to the "gameWin" frames, after all the usual removal of event listeners. Removing and managing event listeners as you jump across frames is VERY important, so pay good emphasis here.

Step 6 - The Game Loop, Handling Display

Finally, when handling the display for this game, we just need to take care of displaying the life , gold and the current wave to the player.

381
382
383
384
385
386
387
//******************
//Handle Display
//******************			
//Display new Score
mcGameUI.txtLife.text = String(life);
mcGameUI.txtGold.text = String(currGold);
mcGameUI.txtWave.text = String(currWave) + " / " + String(maxWave);

That about sums up all the key concepts in this tutorial.

Download the Game Files

The files you need to create this game can be downloaded from here.

*UPDATED* If you want a copy of the Tower Defense with a Boss at the end of the waves, download it from here.

The Game

And here you have it, your very own Tower Defense game. Enjoy! Do share with me if you've used this tutorial to create some Tower Defense maps!




How To Play

Objective: Stop the advancing waves of monsters by placing towers at strategic points.

Controls: Click on the three tower icons below and place the tower on the map.


Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player


Flash Resources
Preloader FPS Display Sounds & Music
Keycodes Name Generator
Game Development Resources
Sprite Sheets


Posted by Dendriel

on 2014-11-05 17:49:43

Can anyone tell me how to "GameUI" instance becomes "mcGameUI"? this "mc" in the name is a pattern?

Thanks in advance!


Posted by Reski

on 2014-11-03 09:05:13

how do I get back to the interface design .. thank you


Posted by Travis

on 2014-10-04 12:29:28

I got the error #1009 aswell after converting the old as3 code to CC format. but found a fix.

the txt updates are the last things in the update function.
Cut the txt string updates under //Handle display, lines 381 to 387 and paste them at 367-368. this will make the checks for gameOver or gameWin the last things to be called, and make it work.

this is an inexperienced guess but,
from what I understand the error is caused
because the txt updates are after the checks,
when even after hitting the calls in gameover/win for removing the update function and changing the frame, it will still run that last update function all the way threw its code, hitting the txt updates as the last thing, after the main fla is set to frame gameOver/Win which the txts are not in those frames and will reference as Null.


Posted by LOL

on 2014-08-29 15:01:06

How to create upgradables?


Posted by Mets

on 2014-08-13 16:43:36

the mouse pointer is change bcoz i change the screen resolution


Posted by nebar

on 2014-08-12 18:56:17

games


Posted by Joshua

on 2014-08-10 12:44:54

Please help me. Every time i try to edit it i debug it and it doesnt show the waves, life, gold, helpmenu,ect correctly. The help usually is random words. And the gold says 0 put it really isnt. Help :(


Posted by Ken

on 2014-08-02 10:38:06

What if i'm trying to create another stage with a different placing and paths of monsters, and i want it in the same .fla file

how can i do that?


Posted by Joseph

on 2014-02-20 23:26:46

Double check that you have named your text field as txtLife, and that it is inside the mcGameUI movie clip.


Posted by King

on 2014-02-20 14:43:23

TypeError: Error #1009: Cannot access a property or method of a null object reference.
at GameController/update()


-- Sir Joseph, I always get this kind of error whenever I try to publish it into an .swf .

line error: mcGameUI.txtLife.text = String(life);

Can you help me out. thanks


Posted by Joseph

on 2013-12-14 17:49:13

You should have unzpped a file called C.as too? No? =)


Posted by Khalid

on 2013-12-13 00:26:44

When i downloaded the program first thing I tried was to of course run it, but it says Access to undefined property C. Is C something on your computer or something in the program that i can't find? Curious.


Posted by sakthivel

on 2013-12-04 12:50:41

nice well


Posted by Level maker

on 2013-09-24 08:23:16

Hello, please can I request one unique as3 tutorial?
It's Level editor for players.
If you are interested tell me, I can link you source code of level editor in as3, but it is not tutorial.

Level editor is great future.


Posted by Joseph

on 2013-09-21 12:00:40

I've updated this portion here with a download which shows how you can create a boss at the end of the waves. For ease of viewing, The boss will appear at the end of the 5th wave. Take a look! You can download all the source files under the download section.


Posted by muhammadyasar

on 2013-08-21 21:32:46


Posted by Joseph

on 2013-08-21 00:23:13

@ Tony: Escape should mean the monster going past all your towers and out of the map.


Posted by Joseph

on 2013-08-21 00:17:06

Hi, I'm using Flash Professional CS3 in these examples. Any of the newer Flash Professional will do, or Flash CC.


Posted by joshua

on 2013-08-08 12:40:08

Hey guys. newbie here. What's the exact flash software needed to make this game?


Posted by TonyFckinStark

on 2013-08-07 00:00:35

hey can you explain "Each monster's death or escape gives the player 15 gold." it's really confusing. escape from the map/path? and whatever you can add please. thank you


Posted by Raymond

on 2013-08-05 20:59:41

Sorry guys, i wan to ask what is "warning: 3596: duplicate variable definition."
this thing come out after i done all the step follow the guide, someone know what happen?


Posted by Raymond

on 2013-08-05 20:47:00

Hello there, i try to follow the guide with step by step, but when i launch the game, there are error

C:\Users\MaOz\Desktop\Coursework - Final sem\Traditional Game - Final Coursework 2013\Daruma Otoshi Tower Defense\src\GameController.as, Line 300 Warning: 3596: Duplicate variable definition.
C:\Users\MaOz\Desktop\Coursework - Final sem\Traditional Game - Final Coursework 2013\Daruma Otoshi Tower Defense\src\GameController.as, Line 351 Warning: 3596: Duplicate variable definition.
C:\Users\MaOz\Desktop\Coursework - Final sem\Traditional Game - Final Coursework 2013\Daruma Otoshi Tower Defense\src\GameController.as, Line 357 Warning: 3596: Duplicate variable definition.
C:\Users\MaOz\Desktop\Coursework - Final sem\Traditional Game - Final Coursework 2013\Daruma Otoshi Tower Defense\src\GameController.as, Line 459 Warning: 3596: Duplicate variable definition.
C:\Users\MaOz\Desktop\Coursework - Final sem\Traditional Game - Final Coursework 2013\Daruma Otoshi Tower Defense\src\GameController.as, Line 466 Warning: 3596: Duplicate variable definition.
C:\Users\MaOz\Desktop\Coursework - Final sem\Traditional Game - Final Coursework 2013\Daruma Otoshi Tower Defense\src\GameController.as, Line 473 Warning: 3596: Duplicate variable definition.
C:\Users\MaOz\Desktop\Coursework - Final sem\Traditional Game - Final Coursework 2013\Daruma Otoshi Tower Defense\src\GameController.as, Line 480 Warning: 3596: Duplicate variable definition.
C:\Users\MaOz\Desktop\Coursework - Final sem\Traditional Game - Final Coursework 2013\Daruma Otoshi Tower Defense\src\GameController.as, Line 487 Warning: 3596: Duplicate variable definition.
C:\Users\MaOz\Desktop\Coursework - Final sem\Traditional Game - Final Coursework 2013\Daruma Otoshi Tower Defense\src\GameController.as, Line 494 Warning: 3596: Duplicate variable definition.
C:\Users\MaOz\Desktop\Coursework - Final sem\Traditional Game - Final Coursework


Posted by Guilherme

on 2013-05-02 02:11:22

Very nice tutorial. I couldnt create a TD without your help! Now i can create my own TD just for fun =D


Posted by Sketchist

on 2012-04-15 08:10:13

Can you send me an E-Mail on how to make a Fast-Forward button? And a Pause Menu button?


Posted by Enda

on 2012-02-23 08:48:27

hi, i try to make tower defense with your tutorial.
but i think way the enemy quite stiff, i mean no rotation on turn. can you help me? i try make it with waypoint. but it`s difficul


Posted by tommw

on 2012-02-03 04:27:04

Hey man!

I have a important Question and I really hope you could help me out.

I want to put the Tower_Fire.as, Tower_Lightning.as and Tower_Ice.as classes in the GameController.as
What's the best way to do that?

Cheers!

Tommw


Posted by TW

on 2012-01-30 21:39:43

Very nice tutorials man!
I really do appreciate folks like you that take time to help people out.
Bless you! :)


Posted by Joseph

on 2011-04-18 23:06:58

I understand the concerns about calling a root function from a class like Tower. It doesn't feel very OO.

Instead of "GameController(root).bullets.push(newBullet);
GameController(root).mcGameStage.addChild(newBullet);"
perhaps you can then set another variable, say shouldFire, to be true in the Tower object.

Inside your main game loop running from your GameController, you can then loop through all the towers to check if this variable is true, and if so, create a new appropriate bullet, then immediately set this variable back to false.

But for the purpose of a minigame, and explanation over an online tutorial, I thought the described way would be easier.


Posted by Sean

on 2011-04-15 23:29:28

You can add this to my previous post. This is by far the best tower defense tutorial I have found. The others are so basic and don't really take into account future additions.


Posted by Sean

on 2011-04-15 23:27:31

Alright, thank you. I am progressing along pretty well. I have everything working right now.

I was wondering though, what is a good way to avoid calling a root function from a class, like in your Tower class?


Posted by Joseph

on 2011-04-14 20:50:31

That's the right way to do it. Your Tower class will just be an AS class, and you can put it to extend MovieClip.

Your LaserTower would probably be linked to the actual MovieClip in your Flash library, under its linkage, you can set its base class to point to .Tower


Posted by Sean

on 2011-04-13 07:14:36

I got it all fixed, I had another movieclip in my tower movieclip that didn't have a MouseEnabled = false;

I am trying to now have classes for each tower, with a tower base class. For example, I have my base class "Tower" and my sub class "LaserTower". Should "Tower" extend MovieClip and "LaserTower" extend "Tower"?

I want my tower subclass to put in the tower stats (damage, cooldown, etc.), effects (hitting multiple units, slow tower, etc.) and create a bullet, since different towers will have different bullets.


Posted by Joseph

on 2011-04-05 22:43:23

Just to check, did you include the codes:

//Turn on all placings
for (var i in placings)
{
if (placings[i].canPlace)
placings[i].gotoAndStop("possible");
}

These are the codes that actually make the tiles light up. Perhaps you can follow this direction, and add in some trace statements to see where you got wrong.


Posted by Sean

on 2011-04-04 09:29:08

I am going through your tutorial kind of just getting the basics down while still doing my own code. I usually only look at the tutorial when I get stuck.

I am having a problem now where when I click on a tower button in the UI and it is following the mouse around, my empty tiles won't highlight when the mouse moves over them.


Posted by Joseph

on 2011-02-14 22:44:40

Not sure which part of the code you're unsure of, but let's look at it one by one.

This code happens in the Placing.as. Notice that an event listener has been added to it, such that when you click on the Placing, it triggers the function placeTower, which in turn calls GameController(root).placeTowerAt(....).

GameController(root) is just a reference back to the main GameController class that controls the entire game. Since Placing is a child of the root, we can do this referencing to the root, which is actually the overall GameController class.

We need to cast it because if your FLA is set with Strict mode on, it gives you an error since it isn't sure if root has the function placeTowerAt.

What placeTowerAt does (the code is defined back in GameController.as) is to then create a tower at that particular location which you clicked on.

A bit indirect, I know, but I was just trying to be a little more OO. :p


Posted by Francis

on 2011-02-02 23:51:17

Hey, i really like your tutorial but i cant understand what is the meaning of this code in Placing class.

GameController(root).placeTowerAt(this.x, this.y);

i cant figure it out. can you explain it to me?

Thanks for your help.

t0kz


Posted by Francis

on 2011-02-02 23:50:54

Hey, i really like your tutorial but i cant understand what is the meaning of this code in Placing class.

GameController(root).placeTowerAt(this.x, this.y);

i cant figure it out. can you explain it to me?

Thanks for your help.

t0kz


Posted by pinkerton

on 2011-02-02 23:28:54

hey, i really enjoyed your tutorial but in Placing class it bothers me in
GameController(root).placeTowerAt(this.x, this.y);

can you please help me with this?


Posted by Mike

on 2010-12-26 09:16:26

Hey, I really enjoyed your tutorial, great work on organisation and teaching procedures


Posted by Joseph

on 2010-11-15 22:33:01

Harv, thanks a lot! Your feedback will be useful! =)
Do let me know. Have fun making games!


Posted by harv

on 2010-11-13 08:26:06

hey man! been lookin for a decent tut for ages... gonna give this a go and i'll let ya know hw it goes... cheers :D


Posted by Joseph

on 2010-09-25 22:22:41

Hi Mike!
You came at the right time, I just finished the tutorial. Everything's up! :)


Posted by Mike

on 2010-09-25 06:26:12

Hi, i can't seem to find any posts with a date on them so i was just wondering if this was still under development? Thanks.

M


Flash Tutorial Links:
Play Games: HTML5 Tutorials:
gaming tools download on app store now!
Home | About Us | Contact Us
Powered by Make Flash Games. All Rights Reserved.
By Joseph Tan