How To Make a Tower Defense Game Tutorial

This Tower Defense Game Tutorial shows you how to make a complete tower defense game with shooting towers and multiple waves of enemies. Now fully updated for Cocos2D 2.X! By .

Leave a rating/review
Save for later
Share

Update 6/8/2013: Fully updated for Cocos2D 2.1-rc1 (original post by Pablo Ruiz, update by Brian Broom).

The tower defense genre is one of the most popular game genres in iOS – and for good reason. There’s something incredibly fun about building the ultimate defense and seeing it obliterate horders of invaders!

In this Tower Defense Game tutorial, you’ll get to build a tower defense game of your own from scratch, with Cocos2D!

Along the way, you’ll learn the following:

  • How to create waves of enemies with configurable spawn times.
  • How to make those enemies move along custom waypoints.
  • How to create towers on specific locations in the map.
  • How to make towers shoot at enemies.
  • How to visually debug the waypoints and attack ranges of towers.

At the end of the Tower Defense Game tutorial, you’ll have a solid framework for this type of game, which you’ll be able to expand upon to add new tower types, enemies, and maps!

For this tutorial, you’ll need a basic understanding of Cocos2D. If you are completely new to Cocos2D, you should check out some of the other Cocos2D tutorials on this site first.

Without further ado, let’s start building our defense!

A View from the Ivory Tower

If you’re not familiar with the genre, tower defense games are strategy games where you purchase and position armed towers at strategic points in order to stop waves of enemies that are trying to reach your base and destroy it.

Each wave of enemies is usually harder than the last, with stronger opponents who move more quickly and have greater resistance to your artillery. The game ends when you survive the waves through all of the levels (victory!) or when enough enemies reach your base to destroy it (Aaaugh! You’ve been defeated!).

Here’s a screenshot of how the game will look after you’re done:

As you can see in the image, enemies appear from the top left side of the screen, and they follow the green path to the player’s base.

Along the road, there are a number of platforms where the player can place a tower. The player can only purchase and place as many towers as they can afford, based on their gold reserves. The towers’ attack range is drawn as a white circle; if an enemy is within the tower’s range, the tower will fire on the enemy until the enemy is destroyed, or they move out of range of the tower.

Note: We have only provided resources for the iPhone (non-retina, non 4″ display), so be sure to use the normal iPhone simulator while going through this tutorial. Of course, if you use your own artwork the same techniques shown in this tutorial will apply to any type of iOS device or screen size.

Towers ‘R’ Us: Assembling the Resources

To get started quickly, I’ve created a starter project for you. It contains an empty Cocos2D project and most of the assets you will use in the tutorial.

So go ahead and download the starter project and extract it to your chosen project location.

Note: The art for the project comes from a free art pack by Vicki, which in turn is based on another free art pack by Oray Studios. If you like this art style, the guys at Oray Studios are available for hire!

The starter project was created from a new project from the Cocos2D 2.1 (RC1) basic template, which provides you with a working project that has a HelloWorldLayer with a label in the middle of the screen. You won’t be using this label as you’ll create your own UI, but this gives you a basic starter Cocos2D project that you know works correctly.

Open the project in Xcode, and compile it and run it to make sure that everything is working. The starter project has removed the actual “Hello World” text from the HelloWorldLayer so you’ll only get a black screen if the project runs correctly. But if the project does compile and run, then you’re all set!

Take a look at the project structure. Inside the TowerDefense folder, you’ll find:

  • The libs folder containing all the Cocos2D files
  • The Resources folder containing all the graphics and sounds

Now, you can set up the map and start creating the towers!

Someone to Tower Over Me: Placement

First, add the background image for the scene. Open HelloWorldLayer.m and add the following lines of code inside the “if” condition in init:

// 1 - Initialize
self.touchEnabled = YES;
CGSize winSize = [CCDirector sharedDirector].winSize;
// 2 - Set background        
CCSprite * background = [CCSprite spriteWithFile:@"bg.png"];
[self addChild:background];
[background setPosition:ccp(winSize.width/2,winSize.height/2)];

The first line in section #1 will allow the layer to receive touch events. The remainder of the code in section #2 adds a background sprite to our scene.

With the background in place, you can visually identify where the player is allowed to place towers. Now you need to set some points along the road where the player will be able to touch and build a tower. (Hey – you got a building permit for that, buddy?)

To keep things manageable, a .plist file will be used to store the placement points for the towers so they can be easily changed. TowersPosition.plist has been included in the Resources folder, which already has some tower positions in it.

Inspect this file; you’lll find an array of dictionaries which contain just 2 keys: “x” and “y”. Each dictionary entry represents a tower position by its x and y coordinates. Now you need to read in this file and place the bases for towers on the map!

Open HelloWorldLayer.h and add the following instance variable (within the curly braces after the @interface line):

NSMutableArray *towerBases;

Make the following changes in HelloWorldLayer.m:

//Add a new method 
-(void)loadTowerPositions
{
    NSString* plistPath = [[NSBundle mainBundle] pathForResource:@"TowersPosition" ofType:@"plist"];
    NSArray * towerPositions = [NSArray arrayWithContentsOfFile:plistPath];
    towerBases = [[NSMutableArray alloc] initWithCapacity:10];
    
    for(NSDictionary * towerPos in towerPositions)
    {
        CCSprite * towerBase = [CCSprite spriteWithFile:@"open_spot.png"];
        [self addChild:towerBase];
        [towerBase setPosition:ccp([[towerPos objectForKey:@"x"] intValue],
                                   [[towerPos objectForKey:@"y"] intValue])];
        [towerBases addObject:towerBase];
    }
    
}

//In init, call this new method in section #3
// 3 - Load tower positions
[self loadTowerPositions];

Compile and run the app, and you will see squares on the sides of the path. These serve as the bases for the player’s towers.

Now that the tower bases are ready, call in the construction equipment and build some towers!

First, open HelloWorldLayer.h and add a property (after the closing curly brace):

@property (nonatomic,strong) NSMutableArray *towers;

Synthesize the towers property in HelloWorldLayer.m below the @implementation line:

@synthesize towers;

Now, create a new class to represent the towers. Add a new file with the iOS\Cocoa Touch\Objective-C class template. Name the class Tower, and make it a subclass of CCNode.

Replace the contents of Tower.h with the following:

#import "cocos2d.h"
#import "HelloWorldLayer.h"

#define kTOWER_COST 300

@class HelloWorldLayer, Enemy;

@interface Tower: CCNode {
    int attackRange;
    int damage;
    float fireRate;
}

@property (nonatomic,weak) HelloWorldLayer *theGame;
@property (nonatomic,strong) CCSprite *mySprite;

+(id)nodeWithTheGame:(HelloWorldLayer*)_game location:(CGPoint)location;
-(id)initWithTheGame:(HelloWorldLayer *)_game location:(CGPoint)location;

@end

Now replace the contents of Tower.m with the following:

#import "Tower.h"

@implementation Tower

@synthesize mySprite,theGame;

+(id) nodeWithTheGame:(HelloWorldLayer*)_game location:(CGPoint)location
{
    return [[self alloc] initWithTheGame:_game location:location];
}

-(id) initWithTheGame:(HelloWorldLayer *)_game location:(CGPoint)location
{
	if( (self=[super init])) {
		
		theGame = _game;
        	attackRange = 70;
       		damage = 10;
        	fireRate = 1;
        
        	mySprite = [CCSprite spriteWithFile:@"tower.png"];
		[self addChild:mySprite];
        
        	[mySprite setPosition:location];
    
        	[theGame addChild:self];
        
        	[self scheduleUpdate];
        
	}
	
	return self;
}

-(void)update:(ccTime)dt
{
    
}

-(void)draw
{
    ccDrawColor4B(255, 255, 255, 255);
    ccDrawCircle(mySprite.position, attackRange, 360, 30, false);
    [super draw];
}

@end

The Tower class contains several properties: a sprite, which is the visual representation of the tower; a reference to the parent layer for easy access; and three variables:

  • attackRange: Determines the distance at which the tower can attack enemies
  • damage: Determines how much damage this tower inflicts on enemies
  • fireRate: Determines how much time it takes the tower to reload and fire again.

With those three variables alone, you can create a wide range of different towers with varying attack properties, such as long-range heavy hitters that take a long time to reload, or eager-beaver snipers that fire quickly but have limited range.

Finally, the code contains a draw method which draws a circle around the tower showing its attack range which will be useful for debug purposes.

It’s time to let the player add some towers!

Open HelloWorldLayer.m and make the following changes:

//At the top of the file:
#import "Tower.h"

//Add the following methods:
-(BOOL)canBuyTower
{
    return YES;
}

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    
	for( UITouch *touch in touches ) {
		CGPoint location = [touch locationInView: [touch view]];
		
		location = [[CCDirector sharedDirector] convertToGL: location];
        
       	 	for(CCSprite * tb in towerBases)
        	{
			 if( CGRectContainsPoint([tb boundingBox],location) &&
                             [self canBuyTower] && !tb.userData)
			{
				 //We will spend our gold later.
                
                		Tower * tower = [Tower nodeWithTheGame:self location:tb.position];
                		[towers addObject:tower];
               			 tb.userData = (__bridge void *)(tower);
			}
		}
	}
}

ccTouchesBegan: detects when the user touches any point on the screen. The code then iterates through the towerBases array and checks if any tower base contains the point where the user touched the screen.

But before a tower can be created, you need to check two things!

  1. Can the player afford such a luxury? The canBuyTower method will check if the player has enough gold to buy the tower. For the moment though, your player has all the gold in Fort Knox, and canBuyTower always returns YES.
  2. Is the player violating any building codes? If tb.UserData is set, then there is already a tower on this base and you can’t add a new one!

If everything passes inspection, create a new tower, place it on the base, and add it to the towers array.

Note: The bridge statement towards the end of the method deserves some explanation. The starter project you downloaded has been set up to enable ARC for the files you are working with, but not all of Cocos2D. When you store a pointer to our (ARC) Tower object in the (non-ARC) property of CCSprite, the __bridge directive tells the compiler to simply store the pointer, and not transfer ownership. More details can be found here.

Compile and run the game. Touch any base and see that a tower is added along with a white circle around it, showing its attack range! Muahahaha, you’re armed and dangerous now!

But what good is all this firepower without any bad guys? Let’s invite some enemies to the party!