Cocos2d-x 文字显示
声明:本文分析的是cocos2d-x-3.12的代码
cocos底层使用的是OpenGL进行页面渲染,但OpenGL并支持文字的处理,OpenGL主要是用于图像和3D模型的渲染。为了支持文字的渲染,cocos会将文字转换成要显示的图片,然后通过OpenGL把图片显示出来。
cocos2d-x 3.x中支持四种文字的处理,都实现在Lable类中,对应了Label的四种类型, ttf字体TTF、美术字BMFONT、美术字CHARMAP、系统字 STRING_TEXTURE。对于STRING_TEXTURE系统字的Label实现,与其他三种Label有些不一样,系统字采用的是系统字体,cocos没有对应的字体实现,而其他三种Lbael都有对应的字体类型。
STRING_TEXTURE系统字Label
系统字的创建
可以通过Label类的以下静态函数创建。
static Label* createWithSystemFont(const std::string& text, const std::string& font, floatfontSize, const Size& dimensions = Size::ZERO, TextHAlignment hAlignment = TextHAlignment::LEFT, TextVAlignment vAlignment = TextVAlignment::TOP);
参数: text显示的文字内容
font显示字体的名字。
fontSize字体大小
返回:返回的是一个Label类。
内容的更新
对于所有类型的Label创建完设置新文本后,不会立即生成相应的文字图片,创建的时候只是会设置一个Label需要更新的标志bool Label ::_contentDirty。当需要绘制Label时,如果发现Label内容需要更新则会调用Label::updateContent函数更新文本内容。
系统字Label::updateContent函数中会调用createSpriteForSystemFont函数,该函数会创建一个Texture2D纹理,并掉用Texture2D::initWithString函数初始化纹理,生成相应的文字图片。最后使用文字纹理生成一个sprite精灵,保存在Sprite * Label::_textSprite变量中。整个过程和以下几行代码类似:
auto t = new (std::nothrow)Texture2D;
t->initWithString("abcdefg", "Arial", 30);
auto spt = Sprite::createWithTexture(t);
显示文字
系统字label是创建一个精灵,然后保存在Label::_textSprite中,所以显示系统中label时就是显示textSprite。以下时Label类绘制的代码。
void Label::drawSelf(bool visibleByCamera, Renderer* renderer, uint32_t flags)
{
if (_textSprite)
{
if (_shadowNode)
{
_shadowNode->visit(renderer, _modelViewTransform, flags);
}
_textSprite->visit(renderer, _modelViewTransform, flags);
}
else if (visibleByCamera && !_utf8Text.empty())
{
draw(renderer, _modelViewTransform, flags);
}
}
从Label::drawSelf函数可以看出,如果是系统字则绘制textSprite,否则会调用draw函数绘制。
Font字体Label
字体Label根据不同字体的实现可以分为三种,分别是字体TTF、美术字BMFONT、美术字CHARMAP。这三种每一种都有对应一种字体实现。
TTF字体Label
TTF字体Label对应使用的字体类是FontFreeType类,该字体类接收一个*.ttf字体文件初始化,对应Label的类型是LabelType::BMFONT。
Label的创建
Static Label * createWithTTF(const std::string& text, const std::string& fontFilePath, float fontSize, const Size& dimensions = Size::ZERO, TextHAlignment hAlignment = TextHAlignment::LEFT, TextVAlignment vAlignment = TextVAlignment::TOP);
static Label* createWithTTF(const TTFConfig& ttfConfig, const std::string& text, TextHAlignment hAlignment = TextHAlignment::LEFT, int maxLineWidth = 0);
BMFONT美术字Label
美术字BMFONT的Label对应使用的字体类是FontFNT类,该类美术字由一个配置文件和一张图片组成,图片包含了所有字体中包含的文字,只需要包含几个需要的文字就行,配置文件会记录每个文字所在的位置和大小。FontFNT类只需要通过美术字的配置文件进行初始化就行了。这种美术字可以通过BMFont.exe等软件生成,软件会同时生成配置文件和相应的图片。对应的Label类型是LabelType::BMFONT。
Label的创建
Static Label* createWithBMFont(const std::string& bmfontPath, const std::string& text, const TextHAlignment& hAlignment = TextHAlignment::LEFT, int maxLineWidth = 0, const Vec2& imageOffset = Vec2::ZERO);
CHARMAP美术字Label
CharMap美术字的Label对应的字体类型是FontCharMap类,该类使用的美术字是一张图片,图片上每个字的长宽都是一样的,且文字是按照ASCII顺序排列的。这类美术字通常可以用于数字的显示。对应的Label类型是LabelType::CHARMAP。
Label的创建
Static Label * createWithCharMap(const std::string& charMapFile, int itemWidth, int itemHeight, int startCharMap);
Static Label * createWithCharMap(Texture2D* texture, int itemWidth, int itemHeight, int startCharMap);
Static Label * createWithCharMap(const std::string& plistFile);
字符编码
cocos2d-x中label字符使用的是使用的是unicode编码,创建label时要传入UTF-8字符,C++11起UTF-8字符串可以通过字符串前面添加u8来实现,如:u8"abc中文"。如果传入的不是UTF-8字符串,因为UTF-8兼容ASCII,所以对于英文不会有影响,但是对于中文来说就可能出现乱码或无法显示等等。
对于TTF字体的Label字体中必须包含相应的文字,否则会显示异常,例如使用英文字体显示中文时,中文就无法显示。
如下:
//字体SourceHanSerifSC-Heavy.otf为一种宋体字,中文字体
auto label = Label::createWithTTF(u8"Abc中文", "fonts/SourceHanSerifSC-Heavy.otf", 48);
label->setPosition(visibleSize / 2);
this->addChild(label);
//字体arial.ttf为英文字体,不包括中文字符,所以中文显示异常
auto label2 = Label::createWithTTF(u8"Abc中文", "fonts/arial.ttf", 48);
label2->setPosition(visibleSize.width / 2, visibleSize.height / 2 - 50);
this->addChild(label2);
//没有使用 u8显示会出现乱码
auto label3 = Label::createWithSystemFont("Abc中文", "宋体", 48);
label3->setPosition(visibleSize.width / 2, visibleSize.height / 2 - 100);
this->addChild(label3);
结果:
字体Font
字体的类图大致如下。
三种字体类FontFreeType、FontFNT、FontCharMap都是继承至Font。在Label中并不直接使用Font类,而是使用了一个代理类FontAtlas类。FontAtlas类实现了将字体转换成Texture的功能。为了防止同样字体的FontAltas重复创建,Cocos增加了一个FontAtlasCache类,该类有一个unordered_map静态变量,保存了系统中以创建的FontAtlas类。
在Label类中一个了FontAtlas变量FontAtlas* _fontAtlas,当创建Font类型的Label是,系统会创建一个相应的FontAtlas变量,并保存在fontAtlas变量中。
Font类中有一个接口函数createFontAtlas,该函数可以创建处相应Font类的FontAtlas,在FontAlts里面也会保存相应的字体。