Outdated Docs > Animation > Sprite Sheet Animation

Sprite Sheet Animation

version: Cocos2d-x v2.x
update: Updated about 2 years ago

You can create an animation from a series of image files, like this:

C++ code:

1
2
3
4
5
6
7
8
9
10
11
12
Vector<SpriteFrame*> animFrames(15);
char str[100] = {0};
for(int i = 1; i < 15; i++)
{
    sprintf(str, "grossini_dance_%02d.png",i);
    auto frame = SpriteFrame::create(str,Rect(0,0,40,40)); //we assume that the sprites' dimentions are 40*40 rectangles.
    animFrames.pushBack(frame);
}

auto animation = Animation::createWithSpriteFrames(animFrames, 0.2f);
auto animate = Animate::create(animation);
sprite->runAction(animate);

Lua code:

1
2
3
4
5
6
7
8
9
10
local animFrames = {}
for i=1, 14 do
    local str = string.format("grossini_dance_%02d.png", i)
    local frame = cc.SpriteFrame:create(str, cc.rect(0,0,40,40))
    animFrames[i] = frame
end

local animation = cc.Animation:createWithSpriteFrames(animFrames, 0.2)
local animate = cc.Animation:create(animation)
sprite:runAction(animate)

Note that Animation is composed by sprite frames, delay time per frame, durations etc, it’s a pack of “data”.
While Animate is an action, it is created base on Animation object.

Sprite Sheet Animation

Although manual animation is very easy to understand, it’s rarely used in real game projects. Instead, sprite sheet animation is the common solution of 2D animations.

This is a typical sprite sheet. It can be a sequence of sprite frames for an animation, or can be images pack that will be used in a same scene.
33

In OpenGL ES 1.1 sprite sheets were widely used for these benefits:

  1. Reduce times of file I/O. Loading a big sprite sheet file is faster than loading lots of small files.
  2. Reduce the memory consumption. OpenGL ES 1.1 can only use power-of-two sized textures (that is a width or height of 2,4,864,128,256,512,1024,…). In other words, OpenGL ES 1.1 allocates power-of-two sized memory for each texture even if this texture has smaller width and height. So using packed sprite sheet image will reduce the fragments of memory.
  3. Reduce the draw calls to OpenGL ES draw method and speed up rendering.

Cocos2d-x v3.0 moved to OpenGL ES 2.0. OpenGL ES 2.0 doesn’t block power-of-two memory for textures anymore, but the benefit of reducing file I/O times and draw calls are still working.

Then how about the animation? As we can see, sprite sheet has no MUST-BE relationship with animations. But considering to these benefits above, sprite sheet animations are efficient. There’re different ways to create sprite sheet animations in cocos2d.

Creating from .png and .plist file

In older cocos2d-x versions, CCSpriteBatchNode works for this purpose. SpriteBatchNode is the replacement for CCSpriteBatchNode since v3.0

A SpriteBatchNode object contains the actual image texture of all the sprite frames. You must add it to a scene, even though it won’t draw anything itself; it just needs to be there so that it is part of the rendering pipeline. For example:

C++ code:

1
SpriteBatchNode* spritebatch = SpriteBatchNode::create("animations/grossini.png");

Lua code:

1
local spritebatch = cc.SpriteBatchNode:create("animations/grossini.png")

Next, you need to use the SpriteFrameCache singleton to keep track how frame names correspond to frame bounds – that is, what rectangular area of the sprite sheet. Example:
C++ code:

1
2
SpriteFrameCache* cache = SpriteFrameCache::getInstance();
cache->addSpriteFramesWithFile("animations/grossini.plist");

Lua code:

1
2
local cache = cc.SpriteFrameCache:getInstance()
cache:addSpriteFramesWithFile("animations/grossini.plist")

Once your sprite sheet and frames are loaded, and the sprite sheet has been added to the scene, you can create sprites that use these frames by using the createWithSpriteFrameName method, and adding it as a child of the sprite sheet:
C++ code:

1
2
3
Sprite1 = Sprite::createWithSpriteFrameName("grossini_dance_01.png");
spritebatch->addChild(Sprite1);
addChild(spritebatch);

Lua code:

1
2
3
Sprite1 = cc.Sprite:createWithSpriteFrameName("grossini_dance_01.png")
spritebatch:addChild(Sprite1)
self:addChild(spritebatch)

createWithSpriteFrameName method will find the corresponding coordinates and rectangle from grossini.plist, then “clip” the texture grossini.png to a sprite frame.

Now we need to create a Vector object and add all frames of the animation to it. In the case of this animation, we know all 14 frames have the same size, so we can use a nested loop to iterate through them all, and break the loop when we finish adding the 14th frame.
C++ code:

1
2
3
4
5
6
7
8
9
Vector<SpriteFrame*> animFrames(15);

char str[100] = {0};
for(int i = 1; i < 15; i++) 
{
    sprintf(str, "grossini_dance_%02d.png", i);
    SpriteFrame* frame = cache->getSpriteFrameByName( str );
    animFrames->addObject(frame);
}

Lua code:

1
2
3
4
5
6
local animFrames = {}
for i=1, 14 do 
    local str = string.format("grossini_dance_%02d.png", i)
    local frame = cache:getSpriteFrameByName(str)
    animFrames:addObject(frame);
end

Finally, we need to create a Animate action instance which we can run on the Sprite. In order to repeats the animation forever, we can also wrap the Animate action in a RepeatForever action like this:
C++ code:

1
2
Animation* animation = Animation::createWithSpriteFrames(animFrames, 0.3f);
Sprite1->runAction( RepeatForever::create( Animate::create(animation) ) );

Lua code:

1
2
local animation = cc.Animation:createWithSpriteFrames(animFrames,0.3)
Sprite1:runAction(cc.RepeatForever:create(cc.Animate:create(animation)))

File animation

AnimationCache can load a xml/plist file which well describes the batch node, sprite frame names and their rectangles. The interfaces are much easier to use.
C++ code:

1
2
3
4
5
6
7
8
// "caches" are always singletons in cocos2d
auto cache = AnimationCache::getInstance();
cache->addAnimationsWithFile("animations/animations-2.plist");
// should be getAnimationByName(..) in future versions
auto animation = cache->animationByName("dance_1");  
// Don't confused between Animation and Animate 
auto animate = Animate::create(animation);  
sprite->runAction(animate);

Lua code:

1
2
3
4
5
6
7
8
-- "caches" are always singletons in cocos2d
local cache = cc.AnimationCache:getInstance()
cache:addAnimationsWithFile("animations/animations-2.plist")
-- should be getAnimationByName(..) in future versions
local animation = cache:animationByName("dance_1") 
-- Don't confused between Animation and Animate 
local animate = cc.Animate:create(animation)
sprite:runAction(animate)

Easy to use, isn’t it?

grossini.png (6.3 kB) owen, 2014-04-01 06:22

Sign up for our newsletter to keep up with the latest developments, releases and updates for Cocos2d-x.