Cocos2d-x basics

Some articles about Cocos2d-x framework

Animation

Posted at — Sep 25, 2020

There are two kinds of animation:

Adding files manually

We’ll use a free candle animation for our first example. There are only three frames there so it’s easy to load them like this:

Vector<SpriteFrame*> animFrames;
animFrames.reserve(3);
animFrames.pushBack(SpriteFrame::create("candle/SC300-1.png", Rect(0,0,64,64)));
animFrames.pushBack(SpriteFrame::create("candle/SC300-2.png", Rect(0,0,64,64)));
animFrames.pushBack(SpriteFrame::create("candle/SC300-3.png", Rect(0,0,64,64)));

// create the animation out of the frames
Animation* animation = Animation::createWithSpriteFrames(animFrames, 0.4f);
Animate* animate = Animate::create(animation);

// run it and repeat it forever
Sprite* candleSprite = Sprite::create();
candleSprite->runAction(RepeatForever::create(animate));

Here we use Rect(0,0,64,64) because the frames are 64х64 pixels size.

The problem is the direct file loading is a bad practice (yet we still used it in our examples because it’s easy and intuitive). That’s good enough for small educational examples, but real programs should use spritesheets.

Spritesheets

Here I should recommend you to read this long but very important article about animation. Briefly, there is a SpriteFrameCache class and a singleton instance of this class can load the sprite sheet files. A sprite sheet is actually a pair of files: one single *.png that combines multiple images and one *.plist which is a XML describing those images.

There are various programs that can be used to create sprite sheets:

For our second example we can take four images of a creature in the hood, create a plist file and load it into program it like this:

SpriteFrameCache* sfc = SpriteFrameCache::getInstance();

const string violetMonsterFN = "littleCandleMonster/littleCandleMonster_violet.plist";
sfc->addSpriteFramesWithFile(violetMonsterFN);

Vector<SpriteFrame*> animFrames;
Animation *monsterAnimation = Animation::create();
char tmps[256];
for (int i = 1; i<=4; i++) {
  sprintf(tmps, "lm-1-%i.png", i);
  SpriteFrame * sf = sfc->getSpriteFrameByName(tmps);
  monsterAnimation->addSpriteFrame(sf);
}

monsterAnimation->setDelayPerUnit(0.1);

Animate* animate = Animate::create(monsterAnimation);

You can get rid of listing file names in the code by using the addAnimationsWithFile method of the AnimationCache instance. Loading will look like this:

const string plistFilename = "skeleton/skeleton_images.plist";
SpriteFrameCache::getInstance()->addSpriteFramesWithFile(plistFilename);

const string animationsPlistFN = "skeleton/skeleton_animations.plist";
AnimationCache::getInstance()->addAnimationsWithFile(animationsPlistFN);

and the usage of animation like this:

Animation* animation = AnimationCache::getInstance()->getAnimation(idleAnimationName);
Animate* animate = Animate::create(animation);
skeletonSprite->runAction(animate);

A small problem of this approach is that it requires some additional plist file. This file is different from those created by TexturePacker. There is no software to create this kind of files, so you’ll have to write it manually. However, that’s an usual XML, so it’s easy to understand and edit. You can find the file for this example here.

Anyway, you’ll create an Animate instance at the end and this instance can be used as any other Action. For example here the violet creature moves like the green UFO from our previous examples:

Creature moves and changes frames at the same time