Is this a CallFunc with Spawn bug?

Here is the code I use:

CallFunc* logFunc = CallFunc::create([] ()
{
    static int i = 0;
    CCLOG("CALL %d", i);
    ++i;
});

Vector<FiniteTimeAction*> vec;
for (int i = 0; i < 5; ++i)
{
    vec.pushBack(logFunc);
}

Sequence* spAct = Sequence::create(vec);

runAction(spAct);

The log is as follows:

CALL 0
CALL 1
CALL 2
CALL 3
CALL 4

If I change the code to read Sequence as Spawn i.e.

CallFunc* logFunc = CallFunc::create([] ()
{
    static int i = 0;
    CCLOG("CALL %d", i);
    ++i;
});

Vector<FiniteTimeAction*> vec;
for (int i = 0; i < 5; ++i)
{
    vec.pushBack(logFunc);
}

Spawn* spAct = Spawn::create(vec);

runAction(spAct);

the log is the following:

CALL 0
CALL 1
CALL 2
CALL 3
CALL 4
CALL 5
CALL 6

I have debugged and the fact is that first two actions in Vector<FiniteTimeAction*> vec; are being called twice at the end, i.e. CALL 0 and 1 are the same actions as CALL 5 and 6 correspondingly. I use cocos2d-x-3.8.1 ( September.17 2015) so I am not sure if this bug is present in the latest version too. Please respond if you have such issues too so that we would open an issue in Github.

@ricardo @slackmoehrle @nite @zhangxm

The bug is _duration is not set to 0 either due to a floating point issue or maybe uninitialized data (but it appears at a glance to be initialized). Essentially there is one Spawn action that stores two CallFunc (the rest are Seq->CallFunc + DelayTime) and each of those CallFunc actions aren’t stopped on the immediate update, but rather a second update (calling them each twice).

Looks like _duration is set to FLT_EPSILON in order to prevent divide by errors, maybe Spawn should override isDone:

// if Spawn's duration is ZERO (e.g. its _one and _two are CallFunc/ExtraAction) 
// make sure it declares done immediately
return MAX(_elapsed,FLT_EPSILON) >= _duration

Edit: should probably just set _elapsed = _duration in the init() method if _duration = 0, since its set to FLT_EPSILON only to prevent divide by zero issues.

@stevetranby thank you for your response. Have you tested the code? If it works wrong for you too, then what version of cocos2d-x you use?

Some ‘version’ between 3.9 and latest github, this test project prob 3.9.

Yes I figured this out and posted the code based on testing your code out. It went from 0-6 back to 0-4 once I fixed it.

I’d have to investigate further if this bug, assuming it is a bug (need another pair or two of eyes on it), is something specific to Spawn or to all ActionIntervals that happen to use a 0.0 duration (most do not).

Edit: this seems to behave incorrectly as well?

    auto sprite = Sprite::create();
    sprite->setPosition(Vec2(50,50));
    sprite->setTextureRect(Rect(0,0,10,10));
    sprite->runAction(MoveBy::create(0, Vec2(400,0)));
    addChild(sprite);)

It doesn’t move, would expect this to cause sprite to move to 450,50 on the next frame after it’s added (or maybe same frame. I’ll have to test this out on v3.10 once it’s finally out.

@stevetranby thank you for you investigation and contribution. Have you created a pull request? I have created this issue yesterday: https://github.com/cocos2d/cocos2d-x/issues/14936 for following up the problem.

Have not created a PR yet. I’m not sure of desired solution. Guess I could just submit something and then change as needed.

I was in the same problem. My workaround is setting duration of CallFunc to -1. Sounds pretty messy, but worked.

@ynaoto have you tested with the latest github? I’ll have to check this again now, but I think a fix has been added in the latest branch. I’ll post my results.

There were fixes a few weeks ago

2 Likes

No, I tested with the latest download 3.10. I will try with the github head later.

https://github.com/cocos2d/cocos2d-x/pull/17190 here is the pull request with fix.