, так как я видел несколько вопросов о замене цветов пикселей в спрайтах, и я не видел ни одного хорошего решения (все решения только окрашивают цвет, и ни один из них не может изменить массив цветов, не заставляя вас создавать несколько Слои изображений, которые создают конечное изображение, которое вы хотите, то есть: один слой для сковородок, другой для показа, другой для рубашки, другой для цвета волос ... и так далее - обратите внимание, что у них есть свои преимущества, такие как способность использовать точные градиенты)
Мое решение позволяет вам изменять массив цветов, то есть вы можете иметь одно изображение с известными цветами (вам не нужны градиенты в этом слое, только цвета, которые вы ЗНАЕТЕ их значения - PS Это относится только к тем цветам, которые вы намереваетесь изменить, другие пиксели могут иметь любой цвет, который вы хотите)
если вам нужны градиенты над изменяемыми цветами, создайте дополнительное изображение только с затенением и поместите его в качестве дочернего элемента спрайта.
также помните, что я совершенно новичок в cocos2d / x (3 дня), и что этот код написан для cocos2dx, но может быть легко перенесен в cocos2d.
также обратите внимание, что я не тестировал его на Android только на iOS, я не уверен, насколько способен android официальный gcc и как он будет работать с тем, как я распределяю _srcC и _dstC, но опять же, это легко переносимо.
так что вот так:
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;
}
, чтобы использовать его, просто сделайте следующее:
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]) );
конечно, если вам нужна скорость, вы бы создали расширение для спрайта, которое создаст пиксельный шейдер, ускоряющий его во время рендеринга;)
Кстати: это решение может вызывать некоторые артефакты на краях в некоторых случаях, поэтому вы можете создать большое изображение и уменьшить его, позволяя GL минимизировать артефакт.
Вы также можете создать «исправление» слоев с черными контурами, чтобы скрыть артефакты и поместить их сверху и т. д.
также убедитесь, что вы не используете эти «ключевые» цвета на остальной части изображения, вы не хотите, чтобы пиксели были изменены.
Также имейте в виду, что тот факт, что альфа-канал не изменился, и что, если вы используете базовые изображения только с чистыми красными / зелеными / синими цветами, вы также можете оптимизировать эту функцию для автоматического устранения всех артефактов на краях (и избежать во многих случаях). случаи, необходимость в дополнительном слое тени) и другие интересные вещи (объединение нескольких изображений в одно растровое изображение - помните палитру анимации?)
наслаждайся;)