※今現在のバージョンではほぼ役に立たない情報なのでご注意下さいませ!
まだ未対応なようなので自力で修正してみた。
3バイト以下のUTF-8マルチバイト文字に対応。
kCCBMFontMaxChars 定数
カタカナなどの文字の設定を含む .fnt を読み込むと、こいつに関連して Assert される。
この値は扱えるユニコード値の限界を設定しているようで、65535にすればユニコードがほぼ使用できる…
そう思っていた時期が俺にもありました。
65535 に変更してみるものの表示されない。
コードを見てみるとなんか ユニコードを取得しようとしていると思われる場所で
unsigned short c = m_sString[ i ];
なんてコードが書かれている。char 値を unsigned short にキャストしても 0 ~ 127, 65408 ~ 65535 の値になるので ASCII 文字以外は思うようには表示されない。
そういうことで現時点では CCBMFontLabel は ASCII 文字列しか対応していないらしい。
使いたいなら 使ってない文字に頑張って割り当てるか、コードを マルチバイト対応にするか、修正されるのを待つ他にない。
ということで修正した。
元のソース
void CCLabelBMFont::createFontChars() メソッドだけを変更すればOK
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.length();
if (0 == stringLen)
{
return;
}
for (unsigned int i = 0; i < stringLen - 1; ++i)
{
unsigned short c = m_sString[ i ];
if (c == '\n')
{
quantityOfLines++;
}
}
totalHeight = m_pConfiguration->m_uCommonHeight * quantityOfLines;
nextFontPositionY = -(m_pConfiguration->m_uCommonHeight - m_pConfiguration->m_uCommonHeight * quantityOfLines);
for (unsigned int i= 0; i < stringLen; i++)
{
unsigned short c = m_sString[ i ];
CCAssert( c < kCCBMFontMaxChars, "LabelBMFont: character outside bounds");
if (c == '\n')
{
nextFontPositionX = 0;
nextFontPositionY -= m_pConfiguration->m_uCommonHeight;
continue;
}
kerningAmount = this->kerningAmountForFirst(prev, c);
const ccBMFontDef& fontDef = m_pConfiguration->m_pBitmapFontArray[c];
CCRect rect = fontDef.rect;
CCSprite *fontChar;
fontChar = (CCSprite*)(this->getChildByTag(i));
if( ! fontChar )
{
fontChar = new CCSprite();
fontChar->initWithBatchNodeRectInPixels(this, rect);
this->addChild(fontChar, 0, i);
fontChar->release();
}
else
{
// reusing fonts
fontChar->setTextureRectInPixels(rect, false, rect.size);
// restore to default in case they were modified
fontChar->setIsVisible(true);
fontChar->setOpacity(255);
}
float yOffset = (float)(m_pConfiguration->m_uCommonHeight) - fontDef.yOffset;
fontChar->setPositionInPixels( ccp( nextFontPositionX + fontDef.xOffset + fontDef.rect.size.width / 2.0f + kerningAmount,
(float) nextFontPositionY + yOffset - rect.size.height/2.0f ) );
// NSLog(@"position.y: %f", fontChar.position.y);
// update kerning
nextFontPositionX += m_pConfiguration->m_pBitmapFontArray[c].xAdvance + kerningAmount;
prev = c;
// Apply label properties
fontChar->setIsOpacityModifyRGB(m_bIsOpacityModifyRGB);
// Color MUST be set before opacity, since opacity might change color if OpacityModifyRGB is on
fontChar->setColor(m_tColor);
// only apply opaccity if it is different than 255 )
// to prevent modifying the color too (issue #610)
if( m_cOpacity != 255 )
{
fontChar->setOpacity(m_cOpacity);
}
if (longestLine < nextFontPositionX)
{
longestLine = nextFontPositionX;
}
}
tmpSize.width = (float) longestLine;
tmpSize.height = (float) totalHeight;
this->setContentSizeInPixels(tmpSize);
}
変更後のソース
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;
// ここにワイド文字列への変換処理を追加
// 不正なデータや4バイト文字を発見した時点で変換を終了します(面倒なので)
// https://ja.wikipedia.org/wiki/UTF-8 が超参考になった。
wstring wstr;
wstr.reserve(m_sString.size());
unsigned char charValue;
unsigned i, l, it;
for ( i = 0, l = m_sString.size(), it = 0; i < l;) {
charValue = m_sString[ i ];
if ( (charValue & 128) == 0 ) {
wstr[it++] = charValue;
i += 1;
continue;
}
if ( (charValue & 64) == 0 ) break;
if ( (charValue & 32) == 0 ) {
if ( (i + 1 >= l) || ((m_sString[ i + 1 ] & 192) != 128) ) break;
wstr[it++] = ((charValue & 31) << 6) + (m_sString[ i + 1 ] & 63);
i += 2;
continue;
}
if ( (charValue & 16) == 0 ) {
if ( (i + 2 >= l) || ((m_sString[ i + 1 ] & 192) != 128) || ((m_sString[ i + 2 ] & 192) != 128) ) break;
wstr[it++] = ((charValue & 15) << 12) + ((m_sString[ i + 1 ] & 63) << 6) + (m_sString[ i + 2 ] & 63);
i += 3;
continue;
}
break;
}
// ここ書き換えた : 長さは wstr のものにする
unsigned int stringLen = it;
if (0 == stringLen)
{
return;
}
for (unsigned int i = 0; i < stringLen - 1; ++i)
{
// ここ書き換えた : m_sString を wstr に差し替え
unsigned short c = wstr[ i ];
if (c == L'\n')
{
quantityOfLines++;
}
}
totalHeight = m_pConfiguration->m_uCommonHeight * quantityOfLines;
nextFontPositionY = -(m_pConfiguration->m_uCommonHeight - m_pConfiguration->m_uCommonHeight * quantityOfLines);
for (unsigned int i= 0; i < stringLen; i++)
{
// ここ書き換えた : m_sString を wstr に差し替え
unsigned short c =wstr[ i ];
CCAssert( c < kCCBMFontMaxChars, "LabelBMFont: character outside bounds");
if (c == L'\n')
{
nextFontPositionX = 0;
nextFontPositionY -= m_pConfiguration->m_uCommonHeight;
continue;
}
kerningAmount = this->kerningAmountForFirst(prev, c);
const ccBMFontDef& fontDef = m_pConfiguration->m_pBitmapFontArray[c];
CCRect rect = fontDef.rect;
CCSprite *fontChar;
fontChar = (CCSprite*)(this->getChildByTag(i));
if( ! fontChar )
{
fontChar = new CCSprite();
fontChar->initWithBatchNodeRectInPixels(this, rect);
this->addChild(fontChar, 0, i);
fontChar->release();
}
else
{
// reusing fonts
fontChar->setTextureRectInPixels(rect, false, rect.size);
// restore to default in case they were modified
fontChar->setIsVisible(true);
fontChar->setOpacity(255);
}
float yOffset = (float)(m_pConfiguration->m_uCommonHeight) - fontDef.yOffset;
fontChar->setPositionInPixels( ccp( nextFontPositionX + fontDef.xOffset + fontDef.rect.size.width / 2.0f + kerningAmount,
(float) nextFontPositionY + yOffset - rect.size.height/2.0f ) );
// NSLog(@"position.y: %f", fontChar.position.y);
// update kerning
nextFontPositionX += m_pConfiguration->m_pBitmapFontArray[c].xAdvance + kerningAmount;
prev = c;
// Apply label properties
fontChar->setIsOpacityModifyRGB(m_bIsOpacityModifyRGB);
// Color MUST be set before opacity, since opacity might change color if OpacityModifyRGB is on
fontChar->setColor(m_tColor);
// only apply opaccity if it is different than 255 )
// to prevent modifying the color too (issue #610)
if( m_cOpacity != 255 )
{
fontChar->setOpacity(m_cOpacity);
}
if (longestLine < nextFontPositionX)
{
longestLine = nextFontPositionX;
}
}
tmpSize.width = (float) longestLine;
tmpSize.height = (float) totalHeight;
this->setContentSizeInPixels(tmpSize);
}