问题出现的条件:
设定宽度,且setLineBreakWithoutSpace(true)
问题描述:
处理自动分行逻辑时,会对字符做变换添加换行符\n,并再次调用createFontChars,此时字符序号存在错位可能。
注:自动添加的换行位前的字符tag正常,后续字符错。
解决方案:
tag编号需要过滤掉换行,这么处理后,不管是否存在字符变换,tag都是一致的。
修改后代码:(供参考 请比对源代码)
设定宽度,且setLineBreakWithoutSpace(true)
问题描述:
处理自动分行逻辑时,会对字符做变换添加换行符\n,并再次调用createFontChars,此时字符序号存在错位可能。
注:自动添加的换行位前的字符tag正常,后续字符错。
解决方案:
tag编号需要过滤掉换行,这么处理后,不管是否存在字符变换,tag都是一致的。
修改后代码:(供参考 请比对源代码)
修改点:
void CCLabelBMFont::createFontChars()
{
int nextFontPositionX = 0;
int nextFontPositionY = 0;
unsigned short prev = -1;
int kerningAmount = 0;
CCSize tmpSize = CCSizeZero;
int longestLine = 0;
unsigned int totalHeight = 0;
unsigned int quantityOfLines = 1;
unsigned int stringLen = m_sString ? cc_wcslen(m_sString) : 0;
if (stringLen == 0)
{
return;
}
set<unsigned int> *charSet = m_pConfiguration->getCharacterSet();
for (unsigned int i = 0; i < stringLen - 1; ++i)
{
unsigned short c = m_sString[i];
if (c == '\n')
{
quantityOfLines++;
}
}
totalHeight = m_pConfiguration->m_nCommonHeight * quantityOfLines;
nextFontPositionY = 0-(m_pConfiguration->m_nCommonHeight - m_pConfiguration->m_nCommonHeight * quantityOfLines);
CCRect rect;
ccBMFontDef fontDef;
for (unsigned int i = 0, j = 0; i < stringLen; i++, j++)
{
unsigned short c = m_sString[i];
if (c == '\n')
{
nextFontPositionX = 0;
nextFontPositionY -= m_pConfiguration->m_nCommonHeight;
j--;
continue;
}
if (charSet->find(c) == charSet->end())
{
CCLOGWARN("cocos2d::CCLabelBMFont: Attempted to use character not defined in this bitmap: %d", c);
continue;
}
kerningAmount = this->kerningAmountForFirst(prev, c);
tCCFontDefHashElement *element = NULL;
// unichar is a short, and an int is needed on HASH_FIND_INT
unsigned int key = c;
HASH_FIND_INT(m_pConfiguration->m_pFontDefDictionary, &key, element);
if (! element)
{
CCLOGWARN("cocos2d::CCLabelBMFont: characer not found %d", c);
continue;
}
fontDef = element->fontDef;
rect = fontDef.rect;
rect = CC_RECT_PIXELS_TO_POINTS(rect);
rect.origin.x += m_tImageOffset.x;
rect.origin.y += m_tImageOffset.y;
CCSprite *fontChar;
bool hasSprite = true;
fontChar = (CCSprite*)(this->getChildByTag(j));
if (fontChar)
{
// Reusing previous Sprite
fontChar->setVisible(true);
}
else
{
// New Sprite ? Set correct color, opacity, etc...
if( 0 )
{
/* WIP: Doesn't support many features yet.
But this code is super fast. It doesn't create any sprite.
Ideal for big labels.
*/
fontChar = m_pReusedChar;
fontChar->setBatchNode(NULL);
hasSprite = false;
}
else
{
fontChar = new CCSprite();
fontChar->initWithTexture(m_pobTextureAtlas->getTexture(), rect);
addChild(fontChar, j, j);
fontChar->release();
}
// Apply label properties
fontChar->setOpacityModifyRGB(m_bIsOpacityModifyRGB);
// Color MUST be set before opacity, since opacity might change color if OpacityModifyRGB is on
fontChar->updateDisplayedColor(m_tDisplayedColor);
fontChar->updateDisplayedOpacity(m_cDisplayedOpacity);
}
// updating previous sprite
fontChar->setTextureRect(rect, false, rect.size);
// See issue 1343. cast( signed short + unsigned integer ) == unsigned integer (sign is lost!)
int yOffset = m_pConfiguration->m_nCommonHeight - fontDef.yOffset;
CCPoint fontPos = ccp( (float)nextFontPositionX + fontDef.xOffset + fontDef.rect.size.width*0.5f + kerningAmount,
(float)nextFontPositionY + yOffset - rect.size.height*0.5f * CC_CONTENT_SCALE_FACTOR() );
fontChar->setPosition(CC_POINT_PIXELS_TO_POINTS(fontPos));
// update kerning
nextFontPositionX += fontDef.xAdvance + kerningAmount;
prev = c;
if (longestLine < nextFontPositionX)
{
longestLine = nextFontPositionX;
}
if (! hasSprite)
{
updateQuadFromSprite(fontChar, j);
}
}
// If the last character processed has an xAdvance which is less that the width of the characters image, then we need
// to adjust the width of the string to take this into account, or the character will overlap the end of the bounding
// box
if (fontDef.xAdvance < fontDef.rect.size.width)
{
tmpSize.width = longestLine + fontDef.rect.size.width - fontDef.xAdvance;
}
else
{
tmpSize.width = longestLine;
}
tmpSize.height = totalHeight;
this->setContentSize(CC_SIZE_PIXELS_TO_POINTS(tmpSize));
}