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.
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.
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.
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:
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.
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.
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…
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
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.