How to Animate Sprites in cocos2d

Apr 18, 2010   //   by Derek van Vliet   //   Development  //  41 Comments

One of the most frequently asked questions I see about cocos2d for iPhone is “how do you animate sprites?”. This was also one of the first questions we had when developing Addicus.

It’s actually quite simple to do using cocos2d’s CCSpriteSheet, CCSprite and CCAnimation classes. These classes take a texture atlas and switch between frames at regular intervals. In other words: animation!

Here is how to animate a sprite in cocos2d in 5 steps. You can also download the code for this blog post.

1. Create Your Animation Texture Atlas

First you need to combine all of the frames of your animation into a single graphic, called a texture atlas. You can do this by hand in an image editor like Photoshop, simply by copying and pasting all of the frames of your animation into a single file. Alternatively, there are atlas generating tools that will take a batch of image files and compile them into a texture atlas in just a couple of clicks.

I recommend using a Flash-based tool called Zwoptex because it is officially supported by cocos2d.

Once you’re done, you should have an image that contains all of the frames of your animation such as the one below:

Grossini Dance
Incidentally, this image is included in the cocos2d distribution.

2. Create a CCSpriteSheet

Once we have the texture atlas, it is time to get coding. The following code would go in the init method of a CCScene sub-class.

The first step in code is to create an instance of a CCSpriteSheet using your texture atlas and child it to a node in the scene. In this case we are childing it to the CCScene itself.

CCSpriteSheet *danceSheet = [CCSpriteSheet spriteSheetWithFile:@"grossini_dance_atlas.png"];
[self addChild:danceSheet];

3. Create a CCSprite Using Your CCSpriteSheet

Next we create a CCSprite that uses the texture of the CCSpriteSheet that we just created. We then child it to the CCSpriteSheet. The rect that we initialize the CCSprite with is the first frame of the animation.

CCSprite *danceSprite = [CCSprite spriteWithTexture:danceSheet.texture rect:CGRectMake(0, 0, 85, 121)];
[danceSheet addChild:danceSprite];

4. Create a CCAnimation

Next we need to create a CCAnimation instance and add all frames of the animation to it. In the case of this texture atlas, we know all of the frames are the same size and there are 14 of them, so we can use a nested loop to iterate through them all and break the loop when we finish adding frame #14.

CCAnimation *danceAnimation = [CCAnimation animationWithName:@"dance" delay:0.1f];
 
int frameCount = 0;
for (int y = 0; y < 3; y++) {
	for (int x = 0; x < 5; x++) {
		CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:danceSheet.texture rect:CGRectMake(x*85,y*121,85,121) offset:ccp(0,0)];
		[danceAnimation addFrame:frame];
 
		frameCount++;
 
		if (frameCount == 14)
			break;
	}
}

5. Run the CCAnimation on the CCSprite

Finally, we need to create a CCAnimate action instance which we can run on the CCSprite. Below, we also wrap the CCAnimate action in a CCRepeatForever action that does what you would expect: repeats the animation… forever.

The last line actually plays the animation on the sprite using the runAction message.

CCAnimate *danceAction = [CCAnimate actionWithAnimation:danceAnimation];
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:danceAction];
[danceSprite runAction:repeat];

Putting it All Together

Here is what the above code looks like in a CCScene init method:

//
//  DanceScene.m
//  GrossiniDance
//
 
#import "DanceScene.h"
 
 
@implementation DanceScene
-(id)init {
	self = [super init];
 
	if (self) {
		// create the sprite sheet
		CCSpriteSheet *danceSheet = [CCSpriteSheet spriteSheetWithFile:@"grossini_dance_atlas.png"];
		[self addChild:danceSheet];
 
		// create the sprite
		CCSprite *danceSprite = [CCSprite spriteWithTexture:danceSheet.texture rect:CGRectMake(0, 0, 85, 121)];
		[danceSheet addChild:danceSprite];
 
		// position the sprite in the center of the screen
		CGSize s = [[CCDirector sharedDirector] winSize];
		danceSprite.position = ccp(s.width/2,s.height/2);
 
		// create the animation
		CCAnimation *danceAnimation = [CCAnimation animationWithName:@"dance" delay:0.1f];
 
		int frameCount = 0;
		for (int y = 0; y < 3; y++) {
			for (int x = 0; x < 5; x++) {
				CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:danceSheet.texture rect:CGRectMake(x*85,y*121,85,121) offset:ccp(0,0)];
				[danceAnimation addFrame:frame];
 
				frameCount++;
 
				if (frameCount == 14)
					break;
			}
		}
 
		// create the action
		CCAnimate *danceAction = [CCAnimate actionWithAnimation:danceAnimation];
		CCRepeatForever *repeat = [CCRepeatForever actionWithAction:danceAction];
 
		// run the action
		[danceSprite runAction:repeat];
	}
 
	return self;
}
@end

41 Comments

  • this tuto is great, i can animate my sprite !! but damn, right before, my sprite could jump!! now with sprite sheet and all that stuff, impossible to jump !! Please help.
    I'm trying to make a jump to danceSprite ( i took same name as this sample code for variables in my code) using these methods :

    - (void) check {
    if (danceSprite.position.y > 160) {
    yVel -= 0.2;
    }
    else {
    if (yVel != 6) {
    yVel = 0;
    xVel = 0;
    }
    }
    danceSprite.position = ccp(danceSprite.position.x + xVel, danceSprite.position.y + yVel);

    }
    (check method is call every 0.01 seconds)
    and that one :

    - (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    yVel = 6;
    xVel = 0;

    }

    }

  • HI,
    Thank you for the post.
    I could not get why you are using the x and y in the code.
    I am using the same code in my program, but the images are not at the same place like grossini image. they are one beside other in continues loop.

  • hi,
    I have 14 images. But the sizes are slightly different ? What should I do.

  • Hi Srikanth. If you've got varying sizes in images just use your favorite paint program to resize them. From the way you worded your question maybe its as simple as that but I'm not quite sure. Maybe you are getting at something else?

  • I added all the sprite images to sheet. Number of images are 60. THe size varies from width(min 60, max 170), height(min 54, max 165). And the offsets are also changing.
    For first image (-69, -6.5) for last image (140, 85). How can I do for this situation ?
    Thank you.

  • You’ve got quite a range for min and max of the width and height. You need to standardize on a given size for all your animation frames for the atlas to work properly. Pick the biggest image you have and make each cell in the atlas fit to that. You’ll end up with alot of alpha’d space for the smaller images but this is the best way to do to get the effect that you want.

  • You’ve got quite a range for min and max of the width and height. You need to standardize on a given size for all your animation frames for the atlas to work properly. Pick the biggest image you have and make each cell in the atlas fit to that. You’ll end up with alot of alpha’d space for the smaller images but this is the best way to do to get the effect that you want.

  • You've got quite a range for min and max of the width and height. You need to standardize on a given size for all your animation frames for the atlas to work properly. Pick the biggest image you have and make each cell in the atlas fit to that. You'll end up with alot of alpha'd space for the smaller images but this is the best way to do to get the effect that you want.

  • This is a great tutorial. I know a lot of people will appreciate this post. Thanks. #Cocos2D

  • Hi, how can I remove the sprite from CCLayer when the animation done? I'd like to have a finite animations using CCRepeat instead of CCRepeatForever. Thanks.

  • Hi Petrus, you should look at the CCSequence action and the CCCallFunc action. You could use a CCSequence action to string together the animation and follow it up with a CCCallFunc action that calls a function. The function that CCCallFunc calls could remove the sprite from the layer. Here's an example:

    id action = [CCSequence actions:danceAction,[CCCallFunc actionWithTarget:self selector:@selector(removeAnimatingSprite)],nil];
    [danceSprite runAction:action];

    -(void)removeAnimatingSprite {
    [myLayer removeChild:danceSprite cleanup:YES];
    }

  • Sorry I missed this. Just seeing it in Disqus now.

  • Sorry I missed this. Just seeing it in Disqus now.

  • I used Zwoptex to make a spritesheet from the images I drew, for some reason though Zwoptex insists on randomly ordering the sprites, meaning that I can't use the nested loop shown here to animate. For the sake of seeing if I could get this to work, I had to manually type this out for eight frames:

    CCSpriteFrame *frame1 = [CCSpriteFrame frameWithTexture:walkAwaySheet.texture rect:CGRectMake(228, 0, 75, 100) offset: ccp(0,0)];
    [walkAwayAnimation addFrame: frame1];
    CCSpriteFrame *frame2 = [CCSpriteFrame frameWithTexture:walkAwaySheet.texture rect:CGRectMake(0, 101, 75, 100) offset: ccp(0,0)];
    [walkAwayAnimation addFrame: frame2];

    I just used the plist that Zwoptex generated to play the sprites in order, but obviously this is a terrible way to do it, as any slight change I wanted to make to the sprites would require me to manually go through and change all these sets of coordinates.

    Is there a good solution to this problem?

  • In that case it might be easier for you to load the plist that zwoptex outputs along with your spritesheet and build the animation by referring to the sprite frames by name, like so:

    [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@”MY_SPRITE_SHEET.plist”];

    [walkAwayAnimation addFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@”walkaway01.png”]];
    [walkAwayAnimation addFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@”walkaway02.png”]];
    [walkAwayAnimation addFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@”walkaway03.png”]];

  • Thanks for the info!
    Is there any way in the gameplay where I can check what the current frame is?
    MacFriis

  • Hi MacFriis, you could check the sprite’s textureRect’s origin property against values that you know correspond to specific frames.

  • I have 100 images that can not fit on a single sheet. How can I use more than one sheet to animate all of them?

  • Hi Darko, you could use Zwoptex to compile the images into a couple of sheets and then load the sheets into cocos2d using [CCSpriteSheet spriteSheetWithFile:]. Then, once they’re loaded, you can refer to the sprite frames by name using [CCSprite spriteWithSpriteFrameName:] and it won’t matter that they’re on separate sheets.

  • [...] you will find this code in many places on the net. This part’s credit goes to GetGames.com. Let me explain it -its very [...]

  • I want to remove a sprite when it has finished its animation,how can i verify this?

  • [...] The people at GetSetGames provided an excellent tutorial.  Check it out here [...]

  • Do you mean [CCSpriteFrame spriteWithSpriteFrameName]?

  • Do you mean [CCSpriteFrame spriteWithSpriteFrameName]?

  • Do you mean [CCSpriteFrame spriteWithSpriteFrameName]?

  • Do you mean [CCSpriteFrame spriteWithSpriteFrameName]?

  • Thanks for the excellent tutorial for starter like myself. I must say you app in the Appstore Addicus is very interesting. I need your help. For new iPhone game developer like me, how and where are I get/purchase some good graphics/sprite character for my game’s main characters / enemies? Kenny Chong

  • Thanks for the excellent tutorial for starter like myself. I must say you app in the Appstore Addicus is very interesting. I need your help. For new iPhone game developer like me, how and where are I get/purchase some good graphics/sprite character for my game’s main characters / enemies? Kenny Chong

  • Thanks for the excellent tutorial for starter like myself. I must say you app in the Appstore Addicus is very interesting. I need your help. For new iPhone game developer like me, how and where are I get/purchase some good graphics/sprite character for my game’s main characters / enemies? Kenny Chong

  • Thanks for the excellent tutorial for starter like myself. I must say you app in the Appstore Addicus is very interesting. I need your help. For new iPhone game developer like me, how and where are I get/purchase some good graphics/sprite character for my game’s main characters / enemies? Kenny Chong

  • Thanks for the excellent tutorial for starter like myself. I must say you app in the Appstore Addicus is very interesting. I need your help. For new iPhone game developer like me, how and where are I get/purchase some good graphics/sprite character for my game’s main characters / enemies? Kenny Chong

  • Thanks for the excellent tutorial for starter like myself. I must say you app in the Appstore Addicus is very interesting. I need your help. For new iPhone game developer like me, how and where are I get/purchase some good graphics/sprite character for my game’s main characters / enemies? Kenny Chong

  • seems to be a deprecated method and doesn’t work in Cocos2D 0.99.5

  • Please update post. spriteSheetWithFile is deprecated.

  • Very interesting,One of my friend sent this link the other day and I am desperately looking your next blog post. Carry on on the superb work.
    thank you for sharing

  • I think use Zwoptex to generate plist file and then to use CCSpriteBatchNode, that would be better.

  • Use CCSpriteBatchNode instead of CCSpriteSheet and then batchNodeWithFile

  • [...] – Introduction to CCSpriteFrameCache. – How to Animate Sprites in Cocos2D. [...]

  • Doesn’t Work. ‘Invalid texture for sprite’

  • You can use Sprite Master to generate spritesheet file and also Cocos2D spritesheet .plist file. http://mobinodo.com/spritemaster

Leave a comment

Our Games

Latest Tweets