Using cc.Sprite.setFlippedX/Y and runAction

Hi,

I’ve got a little problem in my game. Sometimes, I need to call setFlippedX and runAction, to change the appearance of the player (like, when doing a new action, like walking toward a new direction).

Code extract:

this.stopAllActions();
this.setFlippedX(this.animationSequencesFlippedX[this.currentAnimationKey]);
this.runAction(cc.RepeatForever.create(this.animationSequences[this.currentAnimationKey]));

The setFlippedX instruction flips the sprite horizontally, and the runAction one changes the player current action / animation. The problem with this is that both instructions are not executed at the same time, and for a split second, you can see the previous animation getting flipped, THEN the new animation appears.

In case it’s not clear, you can check out the bug here: http://stifu.fr/cc/Whip-A-Wimp/

Move the player to the left, then go up ot down. As you go up/down, you’ll see very briefly the previous frame (looking left) be flipped, before the new animation appears.

How can I fix this? Can I freeze the sprite drawing or something, so that the sprite won’t be repainted until I’m done updating it, or something like that?

Thanks.

Hi Thomas,

I’m sorry I didn’t understand your question.

Do you want to run the setFlippedX and animate at same time?

I think you can use a spawn action to do it.for example:
var selfP = this;
var aSpawn = cc.Spawn.create(cc.CallFunc.create(function(){
selfP .setFlippedX(selfP .animationSequencesFlippedX[selfP .currentAnimationKey]);
}), cc.RepeatForever.create(this.animationSequences[this.currentAnimationKey]));

this.runAction(aSpawn);

Hopes to help
David

Hi David,

Yes, I want to run both instructions at the same time. Because at the moment, it’s visible that they’re not perfectly synchronized.

Your code looks like just what I need. But I tried it in my game, and it doesn’t work for some reason. No errors, but the sprite is not displayed at all. The “cc.CallFunc.create” part seems to be the problem, because if I remove it, the sprite appears.

I’ll look into it and report back. Thanks.

I think the problem was that there were spaces between selfP and .something. Try it like this:

var selfP = this;
var aSpawn = cc.Spawn.create(
	cc.CallFunc.create(function(){
		selfP.setFlippedX(selfP.animationSequencesFlippedX[selfP.currentAnimationKey]);
	}),
	cc.RepeatForever.create(this.animationSequences[this.currentAnimationKey])
);

this.runAction(aSpawn);

I noticed the extra space. It’s not the source of the problem. Even if you comment out the whole line, the sprite will not be displayed.

Basically…

Sprite not displayed at all:

var selfP = this;
var aSpawn = cc.Spawn.create(
    cc.CallFunc.create(function(){
        //selfP.setFlippedX(selfP.animationSequencesFlippedX[selfP.currentAnimationKey]);
    }),
    cc.RepeatForever.create(this.animationSequences[this.currentAnimationKey])
);

this.runAction(aSpawn);

Sprite displayed (but not flipped, naturally):

var selfP = this;
var aSpawn = cc.Spawn.create(
    cc.CallFunc.create(/*function(){
        selfP.setFlippedX(selfP.animationSequencesFlippedX[selfP.currentAnimationKey]);
    }),*/
    cc.RepeatForever.create(this.animationSequences[this.currentAnimationKey])
);

this.runAction(aSpawn);

I spent a lot of time on this, and ended up figuring it out. It actually seems to be a bug in Cocos. :frowning:

Basically, cc.Spawn.create does not work if the second param is a cc.RepeatForever, but works if it’s a cc.Repeat.

Simplified code:

            var flipXFunc = flippedXcondition ?
                function() { me.setFlippedX(true); } :
                function() { me.setFlippedX(false); };
            var flipAction = cc.CallFunc.create(flipXFunc, me);

            var anim = cc.Animation.create(frames, delay);
            var animAction = cc.Animate.create(anim);

            //var repeat = cc.RepeatForever.create(animAction); // does not work!
            var repeat = cc.Repeat.create(animAction, Number.MAX_VALUE);

            me.runAction(cc.Spawn.create(flipAction, repeat));

If you could check this out and confirm, that’d be great. I’ll be able to provide the full game that reproduces the bug, if necessary.

Hi, Thomas

Indeed, cc.Spawn doesn’t support cc.RepeatForever. But it’s not a bug, it’s made this way.
If you want such behavior, you can just call two time runAction

            var repeat = cc.RepeatForever.create(animAction);

            me.runAction(flipAction);
            me.runAction(repeat);

Huabin

Hi Thomas,

I’m sorry for misleading you, because the question was uncertain in that moment.
Huabin is right, please use that way to try again.

So sorry.
David

Hi guys,

Huabin: calling runAction twice works, indeed, but results in the same bug described in the first message of this topic. That is to say you can see the sprite is flipped for a split second before the next action is played, while I want both actions to be played at the exact same time. My hacky code posted above (cc.Repeat.create(animAction, Number.MAX_VALUE);) fixes this visual glitch, although I wish there was a cleaner way to do it.

David: no problem, it’s my fault I hard trouble explaining this.

So, I’ll keep my cc.Repeat hack unless a nicer solution is found.

Thanks.

Sorry for bumping this thread, but I ran into this same issue on cocos2d-html5 2.2.2. My workaround was to use sprite.setScaleX(-1). I’m assuming this is indeed a bug, but I haven’t tested on newer versions.