CCSprite sometimes not rendering image

I am making a game using playing card images. In my setup phase where i draw the initial state, everything is fine. As the game progresses, sometimes CCSprites do not render at all at the target location. It happens on iOS and Android, both on device and simulator, so i’m pretty sure the issue is in my code.

Platforms: iOS and Android. Happens on physical devices and mobile, different resolutions, etc.
Cocos2dx version: 2.1.1 beta 3

I can confirm the filename, target position, etc. are correct for the CCSprite. So my guess is that I am rendering at the wrong time or something.

I attached a screenshot of what happens: Notice how the top row of cards has some gaps. These are examples of the failures. It is simply a loop that renders cards as follows:

    for (int i = 51; i >=0; i--){
        CCSize winSize = getWinSize();
        CCSprite *card = CCSprite::create("ab1fv.png");
        card->setScale(CC_CONTENT_SCALE_FACTOR());
        card->setPosition(ccp(winSize.width / 2 - card->boundingBox().size.width/2 + 10 + (i * 2),
                              winSize.height - card->boundingBox().size.height/3*2) );
        addChild(card);
        remainingCardSprites.push(card);
    }

I run this code once at the beginning of each game. The first game is always fine, the errors happen more and more as the game goes on.

I think it’s strange that it works most of the time but randomly seems to fail. If you look at the 2nd pile of cards, there’s also a missing ace in between the 2 and the 10 (adding up to 18 total). Sometimes when i restart the game the background does not render and is all black. So it seems to happen to all my CCSprites. They all use similar code to what I posted.

The CCSprite object seems to be incorrectly created, since the application crashes when i try to get the bounding box of the referenced sprite.

Let me know if you need any more source!


IMG_0018.PNG (211.4 KB)

It seems to be more of how you clean-up and handle your sprites after each game (as you stated the first game is always fine), would you be able to post what you do in-between each game and any sprites you clean up. Do you re-create the game scene? If so, show when you stop the game scene and re-create it.

I do the following: (using a queue of CCSprite*)

    while (!remainingCardSprites.empty()){
        CCSprite* cardSprite = remainingCardSprites.front();
        removeChild(cardSprite);
        remainingCardSprites.pop();
    }

Notice that i always create the sprite then put it in the queue, or remove the sprite and then pop it from the queue. The two always go hand-in-hand so it doesn’t seem I should have leaked references or anything anywhere.

My scene is just a CCLayer extension. I don’t think i really ever changed anything at that level, nor do I ever take down the scene. I just ‘rebuild it’ during a game over by manually removing the children then adding them back in the initial state.

Can you try it with reloading the complete scene and share the result? Normally for new game, I prefer to reload the scene to avoid any backlog data (However, this is not necessary).

As far as the scene goes, the bug occurs a few times during the first active game session anyway. So even before a scene has been ‘torn down’ the bug is happening. I did a little more digging about these cases:

The way the game works, when the bottom 4 piles are tapped, the top card’s sprite is moved to the pile with a CCMoveTo. Sometimes even though the sprite was originally drawn at the top pile, when it’s animated in disappears.

That means first i draw a card:

    CCSize winSize = getWinSize();
    std::stringstream filename;
    filename << "a" << currentCard << ".png";
    CCSprite *card = CCSprite::create(filename.str().c_str() );
    card->setScale(CC_CONTENT_SCALE_FACTOR());
    card->setPosition(ccp(winSize.width / 2 - card->boundingBox().size.width/2,
    winSize.height - card->boundingBox().size.height/3*2) );
    addChild(card);

    topCardSprite = card;

Then the user taps a pile so i animate the card as so:

    CCFiniteTimeAction* actionMove = CCMoveTo::create(duration, targetDestination);
    topCardSprite->runAction(CCSequence::create(actionMove, NULL));

Sometimes this makes the card disappear. Strange, its the same sprite reference that was earlier displaying. And again, it’s random. And again, sometimes the bug happens on non-animated sprites. They’re just 24 bit pngs.

I’ll double check all the initialization code, i suppose.


EDIT: I don’t want to double post since i’m not sure it’s allowed. I’m debugging the cocos2dx code and beginning to suspect the texture cache might be misbehaving. I will update with anything I find.

It’s very difficult to say where the bug lies without having the test code in hand.

Anyway, did you try check if the targetDestination is within the screen? What is default duration, you are setting for this animation? Check if it not accidentally modifying to zero.

Better capture a video and post a youtube link to understand the problem or post the test code

Ok, here’s the entire code for the layer. it’s kinda big so take a look. Maybe there’s something problematic in the setup? Let me know if you have any questions.

Ok. Looks like I got the source of your problem.

I believe, **drawStackBacks* is the function that you are using to reset the game. And instead of recreating the complete scene, you are just reseting the positions of the card. Let me know if I my understanding is wrong.
If the above assumption is correct, then __ the problem is about same Z-Index of all the children. Let me explain in detail.

  1. You created a game scene.
  2. Generating the cards with same Z-ORDER and adding them into the vector in series.
    Vector Stack / Z-Order
    Card 1/CARD_Z_ORDER
    Card 2/CARD_Z_ORDER
    Card 3/CARD_Z_ORDER
    ………………….
  3. Now after finishing game play, you restarted the game and shuffled the card.
  4. Since the card are shuffled, so they are shuffled in Vector Stack too.
    Vector Stack / Z-Order
    Card 4/CARD_Z_ORDER
    Card 1/CARD_Z_ORDER
    Card 9/CARD_Z_ORDER
    ………………….

If I am right up to this point, then….
Though the cards are having the same Z-ORDER in the scene but they are added one after another. So though you shuffle the cards in your vector but it is not shuffled in the Scene or whatever the parent layer of the cards is. So,
**At initial launch of scene,*

Vector / Parent Layer Stack

Card 1 / Card 1
Card 2 / Card 2
Card 3 / Card 3
………………

After shuffling the cards in the scene

Vector / Parent Layer Stack

Card 4 / Card 1
Card 1 / Card 2
Card 9 / Card 3
……………………

So, as you see the Scene will always first draw the Card 1 and then will draw Card 2 and so on. So though in vector stack, Card 1 appears after Card 4 but since in Parent Layer Stack, the position is reversed so Card 1 will draw first and on top of it Card 4 will draw later on in every routine call.

In short, Layer will draw the children in the stored order. And you only shuffled your vector stack but never shuffled the layer’s children.

HOW TO SOLVE THIS ISSUE

  1. Either adjust the position of cards in the layer’s Children array too as per position in vector.
  2. Use different z-order of every card and adjust the Z-Order of the each card on every move / whenever you feel you need it in the game.

I hope, you got the issue by now. If not then ping me over Skype: codesnooker

And If I am completely wrong then kindly excuse me for writing all bullshit :slight_smile:

Actually drawStackBacks is only called once per run of the application. I reset the game in the reset function, and that isFirst block is only run the very first time it’s called (which is where drawStackBacks is.) The reason I don’t think it’s a layering bug is because for some of the images, they’re offset in a way that even if the z layer was messed up, you would be able to see part of the card underneath the other… instead it’s just missing.