Animate and Animation Question

Hi!

I’m creating an animation and it’s showing correctly. My problem arises when I want to change the speed of an existing animation. I read on another post that we can use the Speed action for such purpose, but before trying that, I want to understand why modifying the Animation object is not working. So this is what I do:

GameScreen.cpp

//fill up spriteFrames  
auto walkAnimation = Animation::createWithSpriteFrames(spriteFrames, 0.1f);
auto animate = Animate::create(walkAnimation); 

//I create an enemy and pass the animate object in the constructor 
mEnemies.push_back(std::make_unique<Enemy>(..., animate, ...)); 

Enemy.cpp

Enemy::Enemy(..., Animate* walkAnimation, ...) : ..., mWalkAnimation(walkAnimation), ... 
{
   mWalkAnimation -> retain();
   //should I also retain the Animation object? I'm guessing so...
   mWalkAnimation -> getAnimation() -> retain();
   mEnemySprite -> runAction(RepeatForever::create(walkAnimation));
}

ExternalFile.cpp

void ChangeAction(Enemy* e) 
{
     e -> EnemySprite().stopAllActions;
    //... lots of stuff, and conditionally, we want to run again the animation slower
    e -> WalkAnimation -> getAnimation() -> setDelayPerUnit(0.5f); //slower than originally
    e -> EnemySprite().runAction(RepeatForever::create(e -> WalkAnimation));
}

The code above produces the same animation, with the same speed, no matter which argument I pass to setDelayPerUnit. In the debugger, I can see perfectly that the Animation object inside the Animate object is actually changed, and therefore I don’t understand why it’s not working. I also noted that if I create (or clone) a new Animate object, it works, but I would like to understand why. My guess is that stopAllActions is removing some data required by Animate, but since I’m retaining both the Animate and the Animation object, I don’t understand how that is possible.

Thanks in advance.

Have a look at CCActionInterval.cpp. The split times (when to change to the next animation frame) are calculated in Animate::initWithAnimation(Animation* animation).
Changing the animation afterwards won’t recalculate the split times.

If your comfortable with hacking the cocos2d-x source you could add a method to Animate for clearing and recalculating _splitTimes.

Or you could write a subclass of Animate adding that method.

EDIT: And don’t forget to call

setDuration(_animation->getDuration() * _animation->getLoops());

in that method…
After all I think your better off creating a new Animate or using Speed…

BTW, I don’t think retaining the animation is necessary since it’s already retained by Animate.

Thanks a lot for your answer. I had taken a look at CCActionInterval.cpp, but I missed the point that you have perfectly depicted.

The solution that I’ve implemented, as you point out, is passing an Animation object to the constructor of my Enemy class (instead of the Animate object), and to create a new Animate object after modifying the animation. That certainly works.

Regarding retaining or not the Animation object, at first I thought the same as you, but now it doesn’t matter any more, since I only have to retain the Animation object that I’m passing to the constructor.

IMHO (and with no offense to the wonderful cocos2d-x developers), I find a bit confusing the separation between Animation and Animate objects, because it is not intuitive, not at first sight at least. In terms of a better API usability, I think we could do better by unifying them under a common interface.

1 Like