Date: 2016/10/3 Cate: C++, cocos2d-x Tags:  

cocos2d-xでテキストを表示するにはLabelクラスを使うかと思います。
このLabelクラス、基本的に文字色は1色しか対応していないっぽいのですが、今回文字の途中の特定部分だけ色を変える、という作業が必要になったので実装してみました。
cocos2d-xのバージョンはv3.11.1です。

Labelクラスでは、それぞれの文字はSpriteになっていて、label->getLetter(2)みたいな感じで◯文字目のSpriteを取得することができます。
今回、「やくそうは12Gだよ」の「12G」の部分だけ赤くしたい、ということを実現したいのですが、この「12G」が何文字目から何文字目なのかがわかればgetLetterでSpriteを取得し、setColorしてやれば色を変えられそうです。

では、「やくそうは12Gだよ」の「12G」の位置なのですが、std::stringの文字列でfindすれば出来るのでは?と思って試してみました。

std::string text = "やくそうは12Gだよ";
auto label = Label::createWithTTF(text, "Arial", 30.f);
label->setColor(Color3B::BLACK);
auto start = text.find("12G");
auto end = start + 3;
for(auto i = start; i < end; +i){
    label->getLetter((int)i)->setColor(Color3B::RED);
}

こんなかんじです。
しかし、これだとstd::stringにおける文字の位置とLabel上の位置が異なるという問題がおきてうまくいきませんでした。
なぜかというと、std::stringだとバイト数でカウントしてるっぽいのに対して、Labelは日本語1文字は1文字としてカウントしてるようなので、文字数の数え方が違うようでした。
なので、Labelクラスの中身を見ていってみたところ、どうやら内部ではstd::u16stringとしてテキストを保持しているようです。ということでstd::u16stringとして文字数をカウントしたらうまくいきました。
以下、そのメソッドです。

void MyStringUtils::changeLabelColor(cocos2d::Label *targetLabel, std::string targetString, const cocos2d::Color3B& color)
{
    std::u16string baseString;
    std::u16string changeColorString;
    StringUtils::UTF8ToUTF16(targetLabel->getString(), baseString);
    StringUtils::UTF8ToUTF16(targetString, changeColorString);
    auto start = baseString.find(changeColorString);
    auto end = start + changeColorString.size();
    for(auto i = start; i < end; ++i){
        targetLabel->getLetter((int)i)->setColor(color);
    }
}

使い方としては、

std::string targetStr = "12G";
std::string text = "やくそうは" + targetStr + "だよ";
auto label = Label::createWithTTF(text, "Arial", 30.f);
label->setColor(Color3B::BLACK);
MyStringUtils::changeLabelColor(label, targetStr, Color3B::RED);

こんなかんじです。

他にももっとうまいやり方とかありそうなので、もし他のやり方があったら教えてもらえるとうれしいです。

Leave a Reply