Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I worked to port Tim Roadley's cocos2d-iphone example from (Box2D Driven Cocos2D Animation) to cocos2d-x to learn cocos2d-x for a project. It is all relatively simple to do, but I am suffering from one obstinate problem. When the ball speeds up, the animation gets very jerky. This problem does not exist in Tim's cocos2d example.

From my investigation and close watching of the animation, it skips frames at the end of the animation sequence when the speed is high (above 4 or 5 in my code).

Here is Tim's original code and some context:

// LOAD ANIMATION FRAMES FROM SPRITESHEET
NSMutableArray *rollFrames = [NSMutableArray array];
for(int i = 1; i <= 120; ++i) {
    [rollFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:@"Ball%i.png", i]]];
}

// CREATE ANIMATION ACTION
speedAction = [CCSpeed actionWithAction:
              [CCRepeatForever actionWithAction:
              [CCAnimate actionWithAnimation: 
              [CCAnimation animationWithFrames:rollFrames delay:0.1]]] speed:3.5];

// CREATE BALL SPRITE
ball = [TRBox2D spriteWithSpriteFrameName:@"Ball1.png"];        
[ball setPosition:ccp((screenSize.width/2), (screenSize.height/2))];
original = ball.position;  // used to determine ball trajectory
[ball runAction:speedAction];
[ball setTag:isTheBall];  // used so we can pick out this sprite during the physics loop
[ball setScale:0.7];

Here is my translation, again with some context:

// LOAD ANIMATION FRAMES FROM SPRITESHEET
CCArray *spriteFrames = CCArray::create();
for (int i = 1; i <= 120; i++) {
    std::stringstream spriteName;
    spriteName << "Ball" << i << ".png";

    CCSpriteFrame *spriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(spriteName.str().c_str());
    spriteFrames->addObject(spriteFrame);
}

CCAnimation *animation = CCAnimation::createWithSpriteFrames(spriteFrames, 0.1);
CCAnimate *animate = CCAnimate::create(animation);
CCRepeatForever *repeat = CCRepeatForever::create(animate);
speedAction = CCSpeed::create(repeat, 3.5f);

spriteFrames->release();

// CREATE BALL SPRITE
ball = (PhysicsSprite *)PhysicsSprite::createWithSpriteFrameName("Ball1.png");
CCSize screenSize = CCDirector::sharedDirector()->getWinSize();
ball->setPosition(ccp((screenSize.width/2), (screenSize.height/2)));
original = ball->getPosition();

ball->runAction(speedAction);

ball->setTag(1);
ball->setScale(0.7f);

Tim's example uses COCOS2D_VERSION==0x00010001 (v1.0.1) I am using COCOS2D_VERSION==0x00020100 (v2.1.0)

I dug through the CCSpeed, CCRepeatForever, and CCAnimate. The major difference I find is in CCActionInterval.cpp where CCAnimate was changed to use "new animation format that supports delays per frame" (commit d0ab4515a4736bdf31aaed6394d95f8ea02beea1). If I revert this change to the previous "animation format" which does not support delays per frame, the sprite animates flawlessly at higher speeds.

Now to my question, am I mis-interpreting how the animation actions are intended to work in cocos2d-x 2.1? Have I missed something that is causing my jerky animation? It does not seem like changing some of the core code is the right answer, though bugs do exist.

share|improve this question
    
How are you testing your code? I noticed significant differences testing cocos2dx animations in the iOS simulator versus on a mobile device (mobile device ran them properly) (only applies if you are doing mobile not desktop development). –  CiscoIPPhone Jan 22 '13 at 21:32
    
Fair question. So far only in the iOS simulator. I will test on the device too. My experience has always been that the simulator is faster (more performant) than the device. Perhaps in graphics that's not true. –  0xACE Jan 22 '13 at 23:33
    
This happens on the Simulator and device (iOS). I have "sidestepped" the issue by subclassing CCAnimate and using the older "animation format." Code to follow shortly. –  0xACE Jan 23 '13 at 20:21

1 Answer 1

Here is the subclass that I used to avoid the issue of jerky-ness with a CCSpeed, CCRepeatForever, and CCAnimate as described above.

// SHAnimate.h
#include "cocos2d.h"
#include "cocos-ext.h"

USING_NS_CC;

class CC_DLL SHAnimate : public CCAnimate {
public:

    virtual void update(float t);

    static SHAnimate* create(CCAnimation *pAnimation);
};

// SHAnimate.cpp
#include "SHAnimate.h"

SHAnimate* SHAnimate::create(CCAnimation *pAnimation){
    SHAnimate *pAnimate = new SHAnimate();
    pAnimate->initWithAnimation(pAnimation);
    pAnimate->autorelease();

    return pAnimate;
}

void SHAnimate::update(float t) {
    CCArray *frames = this->getAnimation()->getFrames();
    int numberOfFrames = frames->count();
    int idx = t * numberOfFrames;

    if (idx >= numberOfFrames) {
        idx = numberOfFrames - 1;
    }

    CCAnimationFrame *frame = static_cast<CCAnimationFrame *>(frames->objectAtIndex(idx));
    CCSprite *sprite = static_cast<CCSprite *>(getTarget());
    if (!sprite->isFrameDisplayed(frame->getSpriteFrame())) {
        sprite->setDisplayFrame(frame->getSpriteFrame());
    }
}

This class is used in place of CCAnimate as follows:

CCAnimation *animation = CCAnimation::createWithSpriteFrames(spriteFrames, 0.1);
CCAnimate *animate = CCAnimate::create(animation);
CCRepeatForever *repeat = CCRepeatForever::create(animate);
speedAction = CCSpeed::create(repeat, 3.5f);    

replaced with

CCAnimation *animation = CCAnimation::createWithSpriteFrames(spriteFrames, 0.1);
SHAnimate *animate = SHAnimate::create(animation);
CCRepeatForever *repeat = CCRepeatForever::create(animate);
speedAction = CCSpeed::create(repeat, 3.5f);    
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.