Last year I set myself the task of learning Objective-C, specifically for the purpose of developing my first iOS game. Following a very steep learning curve my game has now been released and is available on the App Store. Following some initial research into the various game engines available, I settled on Cocos2d: a 2D graphics engine which can be bolted into Xcode and does all the complicated graphics code for you. Many people recommend that you learn raw OpenGL programming as well, and it’s a good idea to, but for an introduction into iOS games development, Cocos2D is perfect.
One of the first things that I needed to learn was basic sprite animation, and like most programming problems there are many ways to accomplish it. The method I use, which is the method I’m about to guide you through here, is through the use of sprite sheets. A sprite sheet is essentially one big image that consists of multiple, smaller images (usually of the same character or object in varying stages of an animation), and is a accompanied by a second file, called a property list, which contains the coordinates for each individual image within the main sprite sheet. One of the main benefits of using sprites sheets is that they’re generally faster; only one image s loaded rather than multiple, and it’s easier, at least I find it so, to keep track of your sprites.
The following tutorial assumes at least a basic knowledge of Objective-C, Xcode, and that you already have the Cocos2d library referenced in Xcode.
Lets get started. Firstly, in Xcode create a new Cocos2d project and name it SpriteSheetTutorial.
Next you need to create the sprite sheet, and for each sprite sheet, Xcode requires two files: an image file containing the individual frames in the animation (in this example this image file is saved as a PNG), and the property list file, which is saved with an extension of .plist. To create the property list and image files I use Zwoptex. Zwoptex comes in two forms: a downloadable application and an online version. Both are completely free and easy to use, and for this tutorial I chose the online version.
This tutorial will demonstrate how to animate a flying bird and so I’ve created the three image files that you’ll need to create the animation. The images can be downloaded below, but you can of course follow the steps with your own images if you prefer.
Load Zwoptex in your web browser (http://zwoptexapp.com/flashversion/) and click on File, Import Images. Select all of the parrot images, (parrot1.png, parrot2.png, and parrot3.png) and click Open. Your Zwoptex window should now look like this:
Zwoptex automatically resizes the images based on the amount of blank space in them, but for this example we want all of the images to be the same size, so we need to tell Zwoptex not to resize them. Click Edit, Select All, to select all of the images, then select Modify, Untrim Selected Images. Secondly, the images will initially load on top of each other, and to fix that just select them all and choose Arrange, and from its menu choose By Name & Width. Your images should now be the same size and appearing beneath each other as shown below:
So far so good. We’re nearly done creating our sprite sheet, we just have one last step: exporting the files so that we can use them. First we will export the texture: select File, Export Texture and in the dialog box that pops up change the filename to Parrot.png, then click Save.
Now for the property list: select File, Export Coordinates, change the filename to parrot.plist, then click Save. That’s it, our sprite sheet is ready.
Now that we have our sprite sheet files we need to add them to the resources folder of our Xcode project. To do this, locate them in Finder and drag them into the resources folder in the Xcode window. Make sure to tick “Copy items into destination group’s folder (if needed)” on the dialog that pops up.
Now for the fun bit: writing the code that creates our sprite and runs our flying bird animation.
If you selected a new Cocos2d template when creating your new project in Xcode, then HellowWorldScene.h and HellowWorldScene.m should have been created for you, and can be found under the classes folder. Open HelloWorldScene.m and replace the -(id) init function with the following code:
{code type=codetype}
-(id) init
{
// always call “super” init
// Apple recommends to re-assign “self” with the “super” return value
if( (self=[super init] )) {
//add the frames and coordinates to the cache
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: @”parrot.plist”];
//load the sprite sheet into a CCSpriteBatchNode object. If you’re adding a new sprite
//to your scene, and the image exists in this sprite sheet you should add the sprite
//as a child of the same CCSpriteBatchNode object otherwise you could get an error.
CCSpriteBatchNode *parrotSheet = [CCSpriteBatchNode batchNodeWithFile:@"parrot.png"];
//add the CCSpriteBatchNode to your scene
[self addChild:parrotSheet];
//load each frame included in the sprite sheet into an array for use with the CCAnimation object below
NSMutableArray *flyAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 3; ++i) {
[flyAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:@"parrot%d.png", i]]];
}
//Create the animation from the frame flyAnimFrames array
CCAnimation *flyAnim = [CCAnimation animationWithFrames:flyAnimFrames delay:0.1f];
//create a sprite and set it to be the first image in the sprite sheet
CCSprite *theParrot = [CCSprite spriteWithSpriteFrameName:@"parrot1.png"];
//set its position to be dead center, i.e. screen width and height divided by 2
CGSize screenSize = [[CCDirector sharedDirector] winSize];
theParrot.position = ccp(screenSize.width / 2, screenSize.height / 2);
//create a looping action using the animation created above. This just continuosly
//loops through each frame in the CCAnimation object
CCAction *flyAction = [CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:flyAnim restoreOriginalFrame:NO]];
//start the action
[theParrot runAction:flyAction];
//add the sprite to the CCSpriteBatchNode object
[parrotSheet addChild:theParrot];
}
return self;
}
{/code}
I’ll go through each line of code below and try to give a clearer understanding of what’s going on.
First you need to add your sprite frames to the sprite frame cache using the property list file that we created using Zwoptex.
{code type=codetype}[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: @”parrot.plist”];{/code}
Now that our frames are cached, we need to add the PNG file to a batch node so that each sprite in our sprite sheet is drawn as one OpenGL object, rather than having a separate object for each sprite. The following line creates a CCSpriteBatchNode object.
{code type=codetype}CCSpriteBatchNode *parrotSheet = [CCSpriteBatchNode batchNodeWithFile:@"parrot.png"];{/code}
Now that the node’s been created we need to add it to our scene, a call to the addChild method of self will let us do just that.
{code type=codetype}[self addChild:parrotSheet];{/code}
Ok, next we setup our animation. To do this we use the CCAnimation class provided by Cocos2d. One function of CCAnimation, called animationWithFrames, accepts an array of image names to be used as the frames in the animation. So the next step is to create an array of our images, parrot1.png, parrot2.png, and parrot3.png. The code below creates the array using the already cached images.
{code type=codetype}NSMutableArray *flyAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 3; ++i) {
[flyAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:@"parrot%d.png", i]]];
}{/code}
Next create the CCAnimation object by passing the frame array that we created above into the animationWithFrames function. You may notice that one of its parameters allows you to set a delay, I would suggest playing around with this to see what suits you.
{code type=codetype}CCAnimation *flyAnim = [CCAnimation animationWithFrames:flyAnimFrames delay:0.1f];{/code}
Now we need a CCSprite object. Create the sprite with the first image from our sprite sheet, i.e. parrot1.png.
{code type=codetype}CCSprite *theParrot = [CCSprite spriteWithSpriteFrameName:@"parrot1.png"];{/code}
The following code just positions the sprite at the centre of the devices screen
{code type=codetype}CGSize screenSize = [[CCDirector sharedDirector] winSize];
theParrot.position = ccp(screenSize.width / 2, screenSize.height / 2); {/code}
Let’s take a second to summarise what we’ve got so far. We now have the frames of our sprite sheet loaded into the cache, we’ve created a CCSpriteBatchNode to contain the sprite sheet image as a whole, and have defined our animation and sprite objects. Now we need to bind the animation to our sprite, and for this we need the CCAction class. Below we create a CCAction object which continuously repeats our previously defined CCAnimation object, called flyAnim.
{code type=codetype}CCAction *flyAction = [CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:flyAnim restoreOriginalFrame:NO]];
{/code}
Then we tell our sprite (theParrot) to run the action.
{code type=codetype}[theParrot runAction:flyAction];{/code}
And to finish it off we add the sprite to our CCSpriteBatchNode so that it displays on the screen.
{code type=codetype}[parrotSheet addChild:theParrot];{/code}
There you have it. If you now run the project in your simulator you should see the parrot happily flying in the center of the screen.















