Create an iPhone Game Using the Cocos2d Framework
Explore iOS development by learning how to build a simple iPhone game
May 11, 2011
Mobile devices are changing the way we work and interact with each other. A new wave of revolution is upon us in which people will consume more data through the mobile device than through any other device. The iPhone app store epitomizes the success and the popularity of mobile apps—and games are its hottest category. In this article I will demonstrate how to get started with creating iPhone games using the Cocos2d framework.
What Is Cocos2d Framework?
Cocos2d is an open source framework that is used to build iPhone games. It is built on top of the core iPhone SDK and exposes easy-to-use APIs to accelerate the development of iPhone games.
Downloading and Installing Cocos2d Framework and Templates
The first step to unleash the power of the Cocos2d framework is to download and install the framework and the templates associated with the framework. You can download the framework and templates here.
Understanding the Basics
Before we begin creating our first iPhone game, it's a good idea to review the basics of the Cocos2d framework, which includes the following elements:
Scenes. Scene is a special node that is the parent of all the nodes. The purpose of scenes is to represent a playable part of the game and also to represent screens (e.g., game over, title page, high score list).
Layer. Layer represents an actual area where the game is played. Layers in Cocos2d serve a similar purpose as they do in Photoshop. This means a single scene can be composed of multiple layers. One layer can represent the background, and the other layer is where the game action takes place.
Sprites. Sprites represent the objects that give character to the game. For example, if you're building a space game, your spaceship and aliens can serve as sprites. Each character that is involved in amplifying the user game experience can be considered a sprite.
Creating Your First Cocos2d Project
Open Xcode and create a new project. From the project template menu select Cocos2d Project, as shown in Figure 1.
Figure 1: Cocos2d template for Xcode
Click Choose to proceed to the next screen. Enter MyFirstCocos2dProject as the name of the project, then click Save. This will create the Cocos2d project with the default template. This article uses version 0.99 of Cocos2d framework, which by default searches for SDK version 4.0. If you have the latest SDK installed, then you will get the Base SDK Missing message shown in Figure 2.
Figure 2: Cocos2d project template base SDK missing
All you need to do is to tell Cocos2d framework that we are using a newer version of the SDK. To do this, go to Edit Project Settings under the Project tab and then specify the SDK version, as shown in Figure 3.
Figure 3: Selecting the installed SDK for iOS device
As, you can see in the above screenshot, the iOS SDK 4.0 is missing, but we can select iOS SDK 4.1. After selecting the correct SDK, build the project using Command B. There should be no errors in the project. At that point, you can press Command R to run the application. Figure 4 shows the application running and the iPhone simulator in action.
Figure 4: The default Cocos2d project template output
The Cocos2d template consists of the basic implementation, which displays a "Hello World" label on screen. At the bottom left of the screen, the current frames per second (FPS) measurement is displayed (60.0 in Figure 4). The default template serves the purpose of verifying that the developer has correctly installed the framework and all the components associated with the framework. In the next section we will dive further into the Cocos2d framework.
Getting Started with Cocos2d Framework
The default Cocos2d template sets up the display in landscape mode. This can be easily changed in the MyFirstCocos2dProjectAppDelegate.m file using the following code:
[director setDeviceOrientation:kCCDeviceOrientationPortrait];
Now, if you run the application you will notice that the display will be in portrait mode instead of landscape mode. Next, we will change the game's background. We have already added the Background3.png in the project's Resources folder. The Resources folder holds all the resources used by the application (e.g., images, sound files). The background image is set inside the static method scene, as shown in the following code:
+(id) scene{// 'scene' is an autorelease object.CCScene *scene = [CCScene node];// 'layer' is an autorelease object.HelloWorld *layer = [HelloWorld node];CCSprite *background = [CCSprite spriteWithFile:@"Background3.png"];[layer addChild:background];// add layer as a child to scene[scene addChild: layer];// return the scenereturn scene;}
The CCSprite class consists of the spriteWithFile method, which takes in the filename as an argument. The background sprite is added to the layer using the addChild method. Figure 5 shows the effect in action.
Figure 5: Background sprite not positioned correctly
Unfortunately, the background image is not positioned correctly. We need to set the anchor point to the sprite, as shown in Figure 6.
Figure 6: Background sprite positioned correctly
The background image is specially designed to fit a screen size of 320 x 480. If you plan to enable the rotation of the device, then you should also have a background image to fit 480 x 320 in landscape mode. In the next section we will add a sprite to the application.
Adding Sprites
Creating a cool background is just the start of an application. We need to add playable sprites to the game. We will be using a simple smiley face image to serve as our movable sprite. The following code adds a sprite to the app.
// on "init" you need to initialize your instance-(id) init{// always call "super" init// Apple recommends to re-assign "self" with the "super" return valueif( (self=[super init] )) {// adding the sprite CCSprite *smiley = [CCSprite spriteWithFile:@"smiley.png"];smiley.position = ccp(100,100); [self addChild:smiley];}return self;}
Inside the init method we created a CCSprite instance to represent the smiley character. The smiley is placed at position (100,100) and then added to the layer. If you run the app, you will notice that the smiley is not visible. The reason is that the smiley is placed behind the background layer. In order to see the smiley, we can simply change the z-index of the background sprite to -1, sending the background sprite behind the smiley sprite, as follows:
[layer addChild:background z:-1];
Figure 7 shows the result.
Figure 7: Smiley face sprite added to the game scene
In the previous example we used hard-coded values when placing our smiley on the screen. The downside of using hard-coded values for positioning the elements on the screen is that the app will be based on the iPhone coordinate system.
If you run the application on an iPad, you will notice that both the background and the sprite are positioned in the wrong place. In order to make it appear the same on both iPhone and iPad devices, we must use the CGSize class to extract the current device width and height values. The following code shows how to use CGSize
// on "init" you need to initialize your instance-(id) init{// always call "super" init// Apple recommends to re-assign "self" with the "super" return valueif( (self=[super init] )) {CGSize windowSize = [[CCDirector sharedDirector] winSize];// adding the sprite CCSprite *smiley = [CCSprite spriteWithFile:@"smiley.png"];smiley.position = ccp(windowSize.width/2,windowSize.height/2); [self addChild:smiley]; }return self;}
In the above code we have used CCDirector to retrieve the winSize instance. The winSize represents the size of the currently running iOS device. This makes sure that the correct coordinates of the running device are returned.
Currently, our smiley does not perform any kind of movement. In the next section we will introduce actions that allow the smiley to wander around the screen.
Actions and Sequences
Cocos2d uses actions to apply cool effects to the sprites or any object that inherits from the CCNode object. The Cocos2d framework has several built-in actions. These actions include CCFadeTo, CCMoveTo, CCScaleBy, and others. The following code uses the CCMoveTo action to move the smiley to a particular position on screen.
// on "init" you need to initialize your instance-(id) init{// always call "super" init// Apple recommends to re-assign "self" with the "super" return valueif( (self=[super init] )) {CGSize windowSize = [[CCDirector sharedDirector] winSize];// adding the sprite CCSprite *smiley = [CCSprite spriteWithFile:@"smiley.png"];smiley.position = ccp(windowSize.width/2,windowSize.height/2); [self addChild:smiley]; // actions [smiley runAction:[CCMoveTo actionWithDuration:0.9 position:ccp(300,300)]];}return self;}
In this code we've used the runAction method to perform CCMoveTo action on the smiley sprite. The CCMoveTo action method uses the actionWithDuration and position parameters. The actionWithDuration is the total time it will take to complete the action. The position parameter represents the coordinates where the sprite will be moved. If you run the application, you will notice that the smiley moves from the original location to the new coordinates.
There are scenarios where you want several actions to be performed on the sprite simultaneously. For these scenarios you can use CCSpawn class, which will make sure that several actions are performed on the sprite at the same time. The following code shows CCSpawn usage in action.
id moveAction = [CCMoveTo actionWithDuration:0.9 position:ccp(200,200)];id fadeOutAction = [CCFadeOut actionWithDuration:0.9];[smiley runAction:[CCSpawn actions:moveAction,fadeOutAction,nil]];
In this code we have created two separate actions, CCMoveTo and CCFadeOut. Both actions are passed as parameters to the CCSpawn method, which enables the smiley CCSprite to move and fade out at the same time.
When working with CCActions, it is very useful to find out when an animation has ended. For this particular scenario we can leverage the CCSequence class. CCSequence allows the developer to invoke difference actions sequentially and then at the end fire a callback function indicating the animation is finished. The following code shows CCSequence:
id moveAction = [CCMoveTo actionWithDuration:0.9 position:ccp(200,200)];id fadeOutAction = [CCFadeOut actionWithDuration:0.9];id callback = [CCCallFunc actionWithTarget:self selector:@selector(finishedAnimation)]; [smiley runAction:[CCSequence actions:moveAction,fadeOutAction,callback,nil]];-(void) finishedAnimation{NSLog(@"animation has been finished!");}
This code creates a callback function using the CCCallFunc class. The callback function will be triggered once both CCMoveTo and CCFadeOut actions are finished. Run the application in debug mode, and you will notice that after the animation is finished a log message animation has been finished will be displayed on screen.
We can use the callback function to repeat the animation continuously and by moving our sprite to random positions on the screen. This can be performed in finishedAnimation function, as shown in the following code:
-(void) finishedAnimation{int x = arc4random() % 320; int y = arc4random() % 480; id moveAction = [CCMoveTo actionWithDuration:0.9 position:ccp(x,y)];id callback = [CCCallFunc actionWithTarget:self selector:@selector(finishedAnimation)]; [smiley runAction:[CCSequence actions:moveAction,callback,nil]];}
Note: The above code can easily be separated into a class method, which will prevent a copy-and-paste fiasco. But to make this article simple, I have duplicated the code.
The arc4random function is used to generate random numbers from 0 to n-1. We are bounding the random numbers for the iPhone portrait size, which is 320 x 480 pixels. The obtained coordinates are then passed into the position parameter of the CCMoveTo function. The finishedAnimation is also used as a callback method, which is invoked constantly after the animation has finished. Run the application, and you will notice that the smiley moves constantly from one random position to another random position.
Collision Detection Using Touches
Our smiley is running wildly on the screen, and there is currently no way to stop it! In this section we will allow the user to pop the smiley by using touch events. There are several methods for handling touch events, but for the sake of simplicity we will use the CCTouchesBegin event, which is triggered when the user touches the screen. Before implementing the CCTouchesBegin event, make sure that the isTouchEnabled property is set to yes inside the init method:
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{UITouch *touch = [touches anyObject];CGPoint location = [touch locationInView:[touch view]];location = [[CCDirector sharedDirector] convertToGL:location];}
The ccTouchesBegan method above gets the coordinates of the view where the user touched the screen. Inside the ccTouchesBegan event we need to find out whether or not the user touched on the smiley. We will achieve this by using the good old Pythagorean theorem. The following code shows how we can find out whether or not our smiley was touched:
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:[touch view]]; location = [[CCDirector sharedDirector] convertToGL:location]; float distance = pow(smiley.position.x - location.x, 2) + pow(smiley.position.y - location.y, 2); distance = sqrt(distance); if(distance <= 50) {[smiley runAction:[CCScaleBy actionWithDuration:0.9 scale:2.0]]; [self performSelector:@selector(removeSmileyFromLayer) withObject:nil afterDelay:1.2]; }}
In the above code we have found the shortest distance between the smiley and the touched position. If the distance is less than 50 pixels, it is confirmed that the smiley has been touched by the user. We then run the CCScaleBy action, which scales the smiley, then removes it from the layer using the custom removeSmileyFromLayer method.
Adding CCParticles
Currently, when the user touches the smiley it simply scales up and then disappears. We can make it more exciting by using the Cocos2d Particles framework. The Particles framework lets you make eye-catching effects by animating hundreds of CCNode objects. All objects work together in harmony to create a particular effect.
We will use the ParticleExplode effect, which will create an exploding effect when our smiley is touched. The following code shows how to add a particle effect to the game. We have used the same smiley as the texture for our explosion, which means that once the smiley is popped, smaller smileys will come out of it.
if(distance <= 50) {CCParticleExplosion *explosion = [[CCParticleExplosion alloc] init];explosion.texture = [[CCTextureCache sharedTextureCache] addImage:@"smiley.png"];[explosion setDuration:2];[explosion setAutoRemoveOnFinish:YES];explosion.position = self.smiley.position; [self addChild:explosion];[self removeChild:self.smiley cleanup:YES];self.smiley = nil; }
In the previous code we have initialized the CCParticleExplosion effect, which is one of the many CCParticles effect available in Cocos2d framework. The duration of the particle effect is set to 2 seconds, and the particle object is marked for automatic removal.
The effect is shown in Figure 8.
Figure 8: CCParticleExplosion effect in action
Wrapping Up
I've given you an introductory look at using the Cocos2d framework, to help you get started with developing iPhone games. If you're motivated to explore working in the Apple iOS development environment, building a simple game using Cocos2d is a good way to get your feet wet.
Mohammad Azam is a principal consultant at Sogeti and an ASP.NET MVP. He is also the founder www.highoncoding.com and maintains his technical blog at www.azamsharp.com. When not programming, Mohammad likes to spend time with his beautiful wife, Naila Sheikh.
About the Author
You May Also Like