CCSpriteBatchNode assert happening when I actually don't use CCSpriteBatchNode

I’m on my way with porting SneakyInput Joystick lib to Cocos2d-x and I’ve basically managed to finish this work, but sometimes I’m getting strange CCAssert error:

CCNode::void CCSprite::addChild(CCNode *pChild, int zOrder, int tag)
{
 // ...
 CCAssert( pChildSprite, "CCSprite only supports CCSprites as children when using CCSpriteBatchNode"); // SIGABRT here
 // ...
}

On my side calling of CCNode’s ‘addChild’ method happening here:

void SneakyButtonSkinnedBase::setButton(SneakyButton *pButton)
{
 if (button) {
    if (button->getParent()) {
        button->getParent()->removeChild(button, true); 
    }
    button->release();
 }

 pButton->retain();
 button = pButton;

 if (pButton) {
     this->addChild(button, 4); /* !!! crash here !!! */
     if (defaultSprite) {
         button->setRadius(defaultSprite->boundingBox().size.width/2);
     }
 }

/* Original iOS code */     

//    if(button){
//      if(button.parent)
//          [button.parent removeChild:button cleanup:YES];
//      [button release];
//  }
//  button = [aButton retain];
//  if(aButton){
//      [self addChild:button z:4];
//      if(defaultSprite)
//          [button setRadius:defaultSprite.contentSize.width/2];
//  }
}

I have absolutely no idea what happening: I have no any references to BatchNode class in my project (and in library too). Moreover, error appearing randomly (~7-8 times from 10 attempts). I wonder - it is a hided logic of framework? It performs some conversion when I’m trying to add several similar sprites to the layer (four navigation buttons)? So why does it work on cocos2-d without errors in this case?

Please check or CCSprite and CCBatchNode have correctly atlas.
I had this same error (but do not know how i corrected)
can also try to use instead addChild appendChild.

Misha Philypchuk wrote:

Please check or CCSprite and CCBatchNode have correctly atlas.
I had this same error (but do not know how i corrected)
can also try to use instead addChild appendChild.

Thank you for your post. I’m not using atlas in my project. And I can’t find ‘appendChild’ method, looks like CCSprite class doesn’t contain it.

this->addChild(button, 4); /* ! crash here ! */

It suggests that ‘this’ is a CCSprite and button is a CCSprite but they are not using CCSpriteBatchNode (or not the same CCSpriteBatchNode).

What is ‘this’ and button when the crash occurs?

Adam Reed wrote:

this->addChild(button, 4); /* ! crash here ! */
>
It suggests that ‘this’ is a CCSprite and button is a CCSprite but they are not using CCSpriteBatchNode (or not the same CCSpriteBatchNode).
>
What is ‘this’ and button when the crash occurs?

‘this’ is object of SneakyButtonSkinnedBase class (extends CCSprte), ‘button’ is SneakyButton object (extends CCNode).

Does your SneakyButton (CCNode based) object contain any CSprite objects?

Adam Reed wrote:

Does your SneakyButton (CCNode based) object contain any CSprite objects?
No, it doesn’t. [[https://github.com/sneakyness/SneakyInput/blob/master/Classes/SneakyButton.h]]

I was thinking more along the lines of adding CCSprite objects to your SneakyButton object.

Do you do button->addChild(CCSprite object) at any point before adding the CCNode to your Sprite?

Adam Reed wrote:

I was thinking more along the lines of adding CCSprite objects to your SneakyButton object.
>
Do you do button->addChild(CCSprite object) at any point before adding the CCNode to your Sprite?

I was tried to link this problem with childs count by adding this line before crashing line:

cocos2d::CCLog("Childs count: %d", button->getChildrenCount());

and whether or not the crash appears after this CCLog, result was the same: button has 0 childes.

After that I went deeper to CCSPrite class and set a new breakpoint:

void CCSprite::addChild(CCNode *pChild, int zOrder, int tag)
{
    CCAssert(pChild != NULL, "Argument must be non-NULL");

    if (m_pobBatchNode) // breakpoint here
    {
        CCSprite* pChildSprite = dynamic_cast(pChild);
        CCAssert( pChildSprite, "CCSprite only supports CCSprites as children when using CCSpriteBatchNode");
        CCAssert(pChildSprite->getTexture()->getName() == m_pobTextureAtlas->getTexture()->getName(), "");
        //put it in descendants array of batch node
        m_pobBatchNode->appendChild(pChildSprite);

        if (!m_bReorderChildDirty)
        {
            setReorderChildDirtyRecursively();
        }
    }
    //CCNode already sets isReorderChildDirty_ so this needs to be after batchNode check
    CCNode::addChild(pChild, zOrder, tag);
    m_bHasChildren = true;
}

Look to the outer ‘if’ checking: I’ve noticed that crash will appear only when m_pobBatchNode != NULL (we trying to append child to BatchNode as result), else code works fine (CCNode::addChild(pChild, zOrder, tag) is calling). So the only thing what I should to decide is WHY and WHERE m_pobBatchNode initialized.

1 Like