[COCOS STUDIO] Jumping to a single frame problem

I have a Node named “Fruit” which contains 4 single frames for each fruit. It also contains a shadow, which should be the same for all fruits. I’m creating this node like this:

        auto newFruit = CSLoader::createNode("Fruit.csb");
        auto fruitAction = CSLoader::createTimeline("Fruit.csb");
        newFruit->runAction(fruitAction);

Now when I’m creating this fruit I want to set a random frame:

        fruitAction->gotoFrameAndPause(r + 1);

r is from 0 to 3.

However it doesn’t work. It doesn’t change frame at all. When I run debugging I can see correct frame number.

So I’ve tried different solution. I’ve made 4 1-frame animations named “a1”, “a2”, “a3” and “a4”.

Then:

        fruitAction->play("a" + to_str(r + 1), false);

Now I’m getting sometimes good sometimes not. Giving constant r continuously is giving me different results.

Only solution I’ve found is to make all animation 2-frames long (with 1 offset) so “a1”: 0->1, “a2”: 2->3, "a3"4->5, “a4”:6->7, but this is too complicated to be worth using.

Is it a bug or I’m doing something wrong?

It seems that going to a frame and pausing it, does not actually renders the frame.

The gotoFrameAndPause function is normally used to set the start frame, pause the animation and play the animation from there afterwards if you resume it.

Have you tried setCurrentFrame?

Yeah I tried it. Actually gotoFrameAndPause sets current frame too. But as you say it does not render it.

And my solution, which I described isn’t perfect too, because sometimes I can see playing from first frame for a fraction of second.

Ok, after hard debugging I figured out where’s the problem. Actually there are 2:

  1. when you won’t play your animation it’ll have playing property set to false so ActionTimeline::step won’t even pass first if (checking if playing) and it’ll never render another frame.
  2. when you use gotoFrameAndPause _endFrame is never set (it’s 0 by default) and because of that setCurrentFrame will always fail, because of this if:
    if (frameIndex >= _startFrame && frameIndex <= _endFrame)

Well, I think it shouldn’t work like that.

So, first time you have to use gotoFrameAndPlay to properly setup _endFrame. Next you can use setCurrentFrame, but you have to resume, call step to force rendering new frame and pause of course.

I’ve created a macro to do that:

#define CC_INIT_ACTION(__ACTION__) __ACTION__->gotoFrameAndPlay(0, __ACTION__->getDuration() + 1, 0, false); __ACTION__->pause()
#define CC_JUMP_ACTION_TO_FRAME(__ACTION__, __FRAME__) __ACTION__->setCurrentFrame(__FRAME__); __ACTION__->resume(); __ACTION__->step(0.0f); __ACTION__->pause()

first for initialization.

I found out that it sometimes goes to a wrong frame.
This fixes the problem:

step(0.0001f) instead of step(0.0f)

Somehow frame number is sometimes incorrectly calculated, but adding very small number seems fixing this problem.

Ok, so as for cocos-2dx 3.10 this technique doesn’t work, but it’s not longer needed. You just can can gotoFrameAndPlay() - nothing more, just works.