"setBlendFunc" does not work when sprite runs a CCAnimate object

code below:

CCSpriteFrameCache *pCCSpriteFrameCacheObj = CCSpriteFrameCache::sharedSpriteFrameCache();
pCCSpriteFrameCacheObj~~>addSpriteFramesWithFile;
CCArray pCCArrayObj = CCArray::create;
char szTextureFileName[ 100 ];
for
{
sprintf;
CCSpriteFrame
pCCSpriteFrameObj = pCCSpriteFrameCacheObj~~>spriteFrameByName( szTextureFileName );
pCCArrayObj~~>addObject;
}
CCAnimation pCCAnimationObj = CCAnimation::createWithSpriteFrames;
CCAnimate
pCCAnimateObj = CCAnimate::create;
ccBlendFunc tBlendFunc = { GL_SRC_ALPHA, GL_ONE };
CCSprite *pSprite1 = CCSprite::create;
addChild;
pSprite1~~>setPosition( ccp( 500, 800));
pSprite1~~>setBlendFunc;
pSprite1~~>runAction( pCCAnimateObj ); // blend mode does not take effect run this
////////////////////////////////////////////////////////////////////////////////////////////////////
but when i comment the line “pSprite1->runAction( pCCAnimateObj );”, blend mode works well. does any one know why?

Can u send a attachment to this site. and I’ll try to find the problem for u

okay…attachment here

I also found that if you create CCSpirteFrame first, then use CCSprite::setDisplayFrame, blend mode cannot work; In CCAnimate’s implementation code, it use setDisplayFrame to change the texture of the CCSprite. but I don’t know why using setDisplayFrame makes blend mode not work

I’m having the same problem :frowning:

I believe the problem lies indeed with CCSprite::setDisplayFrame. More specifically with CCSprite::setTexture, which is called by setDisplayFrame. At the end of setTexture, this code is called:

    if (!m_pobBatchNode && m_pobTexture != texture)
    {
        CC_SAFE_RETAIN(texture);
        CC_SAFE_RELEASE(m_pobTexture);
        m_pobTexture = texture;
        updateBlendFunc(); 
    }

Code from CCSprite::updateBlendFunc:

void CCSprite::updateBlendFunc(void)
{
    CCAssert (! m_pobBatchNode, "CCSprite: updateBlendFunc doesn't work when the sprite is rendered using a CCSpriteBatchNode");

    // it is possible to have an untextured sprite
    if (! m_pobTexture || ! m_pobTexture->hasPremultipliedAlpha())
    {
        m_sBlendFunc.src = GL_SRC_ALPHA;
        m_sBlendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
        setOpacityModifyRGB(false);
    }
    else
    {
        m_sBlendFunc.src = CC_BLEND_SRC;
        m_sBlendFunc.dst = CC_BLEND_DST;
        setOpacityModifyRGB(true);
    }
}

As you can see, the previous blend mode will always be ignored in favor of those. I’ve tried commenting out the call to updateBlendFunc() with no luck, but now that I pasted it here, I realized it was because my sprites are using a spriteBatchNode, silly me. If you’re not using a batch node, maybe fiddling with this part of the code might work.

I’ll investigate about how this works with a batch node and I’ll report back if I find something out. Any light on this that could be shed by someone else would be greatly appreciated though :slight_smile:

Edit: I should mention I’m using cocos2d-x 2.2

@vexille thx for ur reply , u are exactly right:;ok . i find another way to solve this problem, modify the source code from CCAnimate::update( i don’t know whether is there any side effect to do this:;qst ):

void CCAnimate::update(float t)
{
    // if t==1, ignore. Animation should finish with t==1
    if( t < 1.0f ) {
        t *= m_pAnimation->getLoops();

        // new loop?  If so, reset frame counter
        unsigned int loopNumber = (unsigned int)t;
        if( loopNumber > m_uExecutedLoops ) {
            m_nNextFrame = 0;
            m_uExecutedLoops++;
        }

        // new t for animations
        t = fmodf(t, 1.0f);
    }

    CCArray* frames = m_pAnimation->getFrames();
    unsigned int numberOfFrames = frames->count();
    CCSpriteFrame *frameToDisplay = NULL;

    for( unsigned int i=m_nNextFrame; i < numberOfFrames; i++ ) {
        float splitTime = m_pSplitTimes->at(i);

        if( splitTime <= t ) {
                        // notice!!
			ccBlendFunc ccBldFunc = ((CCSprite*)m_pTarget)->getBlendFunc(); // i add this line, be fore setDisplayFrame, we get old BlendFunc
            CCAnimationFrame* frame = (CCAnimationFrame*)frames->objectAtIndex(i);
            frameToDisplay = frame->getSpriteFrame();
            ((CCSprite*)m_pTarget)->setDisplayFrame(frameToDisplay);
                        // notice!!
			((CCSprite*)m_pTarget)->setBlendFunc( ccBldFunc );  // i add this line, afther setDisplayFrame, old BlendFunc is set back

            CCDictionary* dict = frame->getUserInfo();
            if( dict )
            {
                //TODO: [[NSNotificationCenter defaultCenter] postNotificationName:CCAnimationFrameDisplayedNotification object:target_ userInfo:dict];
            }
            m_nNextFrame = i+1;
        }
        // Issue 1438. Could be more than one frame per tick, due to low frame rate or frame delta < 1/FPS
        else {
            break;
        }
    }
}

The same issue remains in cocos2dx-3. How is this not a bug?

Thanks for @raysaint’s solution, You can refer to this issue https://github.com/cocos2d/cocos2d-x/issues/9367, and any advises about this topic is welcome.