Sprite Sheet Animation

Hey everyone.

I’m very new to cocos-2d and I would like to let you know about an issue that had me stumped for a whole day and which could be improved in the documentation. Let me know if I can help.

I was trying to add a sprite animation and from scouring the internet I found out that one possible way was to load each sprite manually and then tie them together to an animation by hand. It is mentioned that a better way to do this is to use plist files which reduce the amount of legwork necessary to get the animation into the game.

So first of all, I created a plist file of my animation frames using TexturePacker (I’m on PC). When I tried to load them into the game, I got an error because the game did not like my plist file.

My problem was that I didn’t know that there are two caches: SpriteFrameCache and AnimationCache and that each has their own plist files and you need both to load an animation. The problem was that I incorrectly tried to load the frame plist file into the AnimationCache.

What made my problem worse was that there seems to be no software on PC that can write the plist file for AnimationCache and the format is not well documented (or I missed it). Luckily I stumbled upon an example from the cpp-tests project that had an animation plist file included.

So in order to save other people from the same headaches I had, I would propose extending the Beginner’s Guide by a section explaining how to get sprite sheet animations into the game. I would outline it like this:

  • There are two caches, SpriteFrameCache and AnimationCache
  • In order to define an animation in AnimationCache, its sprites must be present in the SpriteFrameCache
  • Load Sprites into the SpriteFrameCache by calling SpriteFrameCache::getInstance()->addSpriteFramesWithFile(“spritesheet.plist”);
  • The plist file can be automatically generated by [list of tools]
  • Load the animation into the AnimationCache by calling AnimationCache::getInstance()->addAnimationsWithFile(“animation.plist”);
  • The animation.plist file has a different layout than the spritesheet.plist file and can be written by hand following [attached example file].

This is just a short extension to the documentation which unfortunately skips this part. Currently the doc explains how to load a spritesheet and it explains in a different section how to piece together an animation by hand, but it fails to address how to conventiently load an animation using a spritesheet plist and an animation plist.

Again, if there is some way I can help to extend the Beginner’s Guide please let me know, otherwise I would be happy if someone could extend it.

Cheers.

Did you see this: http://cocos2d-x.org/docs/programmers-guide/4/index.html
Scrolling down to the Animate section?

You can use TexturePacker and other tools to create your .plist: http://cocos2d-x.org/docs/programmers-guide/3/index.html#creating-a-sprite-from-a-sprite-sheet scrolling down to Tools For Creating a Spritesheet

Thanks for the quick reply.

Please re-read what I wrote. I was referring to that section specifically.

Creating frames from a plist is documented, as I mentioned above.
Creating an animation by hand is also documented, as I mentioned as well.

What is missing is how to generate an animation from a plist by calling this:

SpriteFrameCache::getInstance()->addSpriteFramesWithFile("spritesheet.plist");
AnimationCache::getInstance()->addAnimationsWithFile("animation.plist");

Furthermore, what is missing from the manual is that you can generate spritesheet.plist with TexturePacker but you can’t generate animation.plist with it. You can do it by hand but it is not described how. Plus, the animation file has a different format.

Since both files have the same extension .plist, I found it very confusing that both files describe different things using a different internal format. And you have to take care not to call a function with the wrong file.

Finally, my question was not really a call for help, but rather a notice that the manual could be improved / extended.

Anyway, I think you did a great job with the Beginner’s Guide, so I was trying to contribute.

I have to say that I don’t think AnimationCache is widely used anymore. I haven’t used it at all in the 2+ years I have been learning the engine.

That may be the reason.

So you piece together your animations manually?
I found the AnimationCache super convenient because you can load named animations with just two lines of code.

Yes, I do and I have a function that returns the animation to me based upon parameters that I pass in. This lets me compartmentalize it.

You already tried to use TexturePacker. It contains all you need - including the creation of easy to handle animations.

TexturePacker 4.1.0 creates header & source files for cocos2d-x. Add them to your project.

#include "generated/SpriteSheet.hpp"
using namespace TexturePacker;

Loading the frames

SpriteSheet::addSpriteFramesToCache();

Creating a sprite - the method names are derived from your sprite names. If you have a sprite called Background:

auto sprite = SpriteSheet::createBackgroundSprite();

Sprites ending with a number sequence are automatically combined to an animation. E.g. if you name your sprites Enemy_0001, Enemy_0002,…

Creating an animation is as easy as it can get:

auto enemy = SpriteSheet::createEnemy0001Sprite();
enemy->runAction(SpriteSheet::createEnemyAnimationAction(0.1f, -1));

That’s it. The 2 parameters are the frame rate and the number of loops. -1 means infinite.

The nice side effect of this is that you’ll never have trouble with missing sprites in your game. You don’t handle sprite names as strings but use generated methods instead. So every typo in a sprite name is handled by the compiler - and does not kill your game at runtime.

If you use cocos2dx’s dev branch you also get 2 other nice features:

  1. Pivot point editing
  2. Realtime animation preview

I’ve had similar problems to the OP, and build my animations manually.

@AndreasLoew because I define my game objects in json config files the texturepacker header file approach in unsuitable because I need to perform animation/sprite lookups by string. Perhaps this is something we can suggest for the TexturePacker devs. I’d like to see being able to define arbitrary animations in TexturePacker and the ability to load them by string name using the generated source.

@almax27 you can simply use the template exporters in TexturePacker.

Cocos2d-x is currently an internal exporter - but with the examples available it should be easy to create any other output format. Including the animations.plist. It’s just that we don’t have options for setting the timing yet.

I’d like to see being able to define arbitrary animations in TexturePacker and the ability to load them by string name using the generated source.

Should be possible to add that with one of the next bigger updates.

1 Like

Continuing the discussion from Sprite Sheet Animation:

That sounds very convenient. Actually I was looking for a way to access sprites via variables instead of strings as this seems very unstable (basically you can get a null pointer exception any time if you’re not careful and it could bite you at a late stage in the game). The other approach is much better because it gives you the ability to check at compile time. So thanks a lot for that tip.

However, I can’t seem to find the setting in TexturePacker that creates the code. Does it maybe only work in the paid version? What I tried:

  • add images to TexturePacker
  • set Data Format to cocos2d-x
  • remove all the pro version settings
  • publish the sprite sheet

The result is a png and a plist, but as far as I can see I don’t get any c++ code.

I’ll dig out my animation code if anyone wants to reference it, should be helpful for someone.

Being able to define animation properties such as speed would be good too :wink:

Thank you kindly sir!

Use the “cocos2d-x” exporter, not “cocos2d”.

The features are in TexturePacker 4.1.0 - the newest release with the Pivot Point Editor and animation previewer. You also
get some other nice advantages: Polygon sprites - which increase the performance by not drawing all the transparency…

But yes: You need the paid version - sorry.

@Cerno Here dug out some animation code, straight from my old project.

// in the .h Vector< SpriteFrame*> _walkFrames; Animation* _walkAnimation; Animate* _walkAction;

// in the .cpp

SpriteFrameCache* cache = SpriteFrameCache::getInstance();
cache->addSpriteFramesWithFile(“frames.plist”); // relative

// load the frames

for (int i = 0; i < 42; i++)
{
     std::string num = StringUtils::format("%d", i);
     _walkFrames.pushBack(cache->getSpriteFrameByName("Walk_000" + num + ".png"));
}

// create the animation out of the frames and an action for the new animation

_walkAnimation = Animation::createWithSpriteFrames(_walkFrames, 0.02f);
_walkAnimation->retain();

// use/run the animation

auto walk = Animate::create(_walkAnimation);
_legsSprite->runAction(RepeatForever::create(walk));

This works with a plist generated from TexturePacker which is what I use myself

1 Like

@UKDeveloper99: Thanks for the input.

I guess that is about as far as I currently am. I prefer using animation .plist files though, since they allow me to modify the animation without touching the code. Also it allows me to replace the for loop and the vector by a single call of AnimationCache::getInstance()->addAnimationsWithFile(“animation.plist”); which is much less code and improves readability a lot.

What I really prefer though is automatically generated code like AndreasLoew described since it saves me from crashing my game if I have a typo in a filename somewhere.

@AndreasLoew: I did use cocos2d-x as I wrote above and I am using version 4.1.0.

I guess the problem is that I’m not using the paid version.
Unfortunately 40 bucks is a bit much if I use only the core functions.

But generating c++ code along with the sprite sheets is a pretty neat idea.
I’ll probably write a code generator in python to get that functionality.

Thanks a lot for the input!