Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Color Changing Sprites Cocos2d

I need my sprite to transition to one color to another and on and on... like blue tint then green then purple, but i cannot find any good actions for that and am wondering, should i use animations? or is there an incorporated action for this?

like image 549
mattblessed Avatar asked Dec 04 '22 17:12

mattblessed


2 Answers

you can use CCTintTo action to change the color of the sprite

[sprite runAction:[CCTintTo actionWithDuration:2 red:255 green:0 blue:0]];
like image 81
saiy2k Avatar answered Jan 05 '23 11:01

saiy2k


since i saw several questions about replacing pixel colours in sprites, and i did'nt see any good solution (all solution only tint the color, and none of them is able to change an array of colours without forcing you into creating multiple image layers which construct the final image you want, i.e: one layer for pans, other for show, other for shirt, another for hair colour... and it goes on - note that they do have their advantages like the ability to use accurate gradients)

my solution allows you to change array of colors, meaning you can have a single image with a known colors (you dont want any gradiants in this layer, only colours that you KNOW their values - PS this only applies to colors you intent to change, other pixels can have any colour you want) if you need gradiants over the colours you change, create an additional image with only the shading and place it as a child of the sprite.

also be aware that i am super-new to cocos2d/x (3 days), and that this code is written for cocos2dx but can be ported to cocos2d easily.

also note that i didnt test it on android only on iOS, i am not sure how capable is android official gcc and how will it deal with the way i allocate _srcC and _dstC, but again, this is easily portable.

so here it goes:

cocos2d::CCSprite * spriteWithReplacedColors( const char * imgfilename, cocos2d::ccColor3B * srcColors, cocos2d::ccColor3B * dstColors, int numColors )
{
    CCSprite *theSprite = NULL;

    CCImage *theImage = new CCImage;
    if( theImage->initWithImageFile( imgfilename ) )
    {
        //make a color array which is easier to work with
        unsigned long _srcC [ numColors ];
        unsigned long _dstC [ numColors ];
        for( int c=0; c<numColors; c++ )
        {
            _srcC[c] = (srcColors[c].r << 0) | (srcColors[c].g << 8) | (srcColors[0].b << 16);
            _dstC[c] = (dstColors[c].r << 0) | (dstColors[c].g << 8) | (dstColors[0].b << 16);
        }

        unsigned char * rawData = theImage->getData();
        int width = theImage->getWidth();
        int height = theImage->getHeight();

        //replace the colors need replacing
        unsigned int * b = (unsigned int *) rawData;
        for( int pixel=0; pixel<width*height; pixel++ )
        {
            register unsigned int p = *b;
            for( int c=0; c<numColors; c++ )
            {
                if( (p&0x00FFFFFF) == _srcC[c] ) 
                {
                    *b = (p&0xFF000000) | _dstC[c];
                    break;
                } 
           }
            b++;
        }

        CCTexture2D *theTexture = new CCTexture2D();
        if( theTexture->initWithData(rawData, kCCTexture2DPixelFormat_RGBA8888, width, height, CCSizeMake(width, height)) )
        {
            theSprite = CCSprite::spriteWithTexture(theTexture);
        }
        theTexture->release();
    }
    theImage->release();

    return theSprite;
}

to use it just do the following:

ccColor3B src[] = { ccc3( 255,255,255 ), ccc3( 0, 0, 255 ) };
ccColor3B dst[] = { ccc3( 77,255,77 ), ccc3( 255, 0 0 ) };
//will change all whites to greens, and all blues to reds. 
CCSprite * pSprite =  spriteWithReplacedColors( "character_template.png", src, dst, sizeof(src)/sizeof(src[0]) );

of course if you need speed, you would create an extension for a sprite that create a pixel shader that does it hw accelerated at render time ;)

btw: this solution might cause some artefacts on the edges on some cases, so you can create a large image and scale it down, letting GL minimise the artefact. you can also create "fix" layers with black outlines to hide the artefacts and place it on top etc. also make sure you don't use these 'key' colors on the rest of the image you don't want the pixels changed. also keep in mind that the fact that the alpha channel is not changed, and that if you use basic images with pure red/green/blue colors only, you can also optimize this function to eliminate all artefacts on edges automatically (and avoid in many cases, the need for an additional shade layer) and other cool stuff (multiplexing several images into a single bitmap - remember palette animation?)

enjoy ;)

like image 29
Michael Badichi Avatar answered Jan 05 '23 13:01

Michael Badichi