Cocos2dx学习笔记(15)——标签Label

本章将就游戏内的标签内容进行讲解。

本文仅供个人记录和复习,不用于其他用途

什么是标签

举个很简单的例子,在游戏结束的分数结算界面,你经常会看到你的游戏分数以及一个大大的GAME OVER,当然还有菜单或者再来一局。其实这些文字可以用标签做出来,不一定就得用图片来代替。那么呢,总的来说,标签其实就是显示在游戏中的那些文字。

标签也分2.x版本和3.x版本,这里我也就分开讲一讲用法。区别的方法很简单,带CC前缀的就是2.x,不带的就是3.x。

CCLabelTTF

标签介绍

CCLabelTTF是最简单且使用最方便的字体类,可以使用.ttf格式的字体。其父类为CCSprite,所以也继承了CCSprite所有的操作,故也可以将其当做CCSprite来用。

1
2
// 第一个参数是要显示的字符串,第二个参数为字体,第三个参数为大小
CCLabelTTF *ttf = CCLabelTTF::create("LabelTTF", "Courier", 100);

这种标签简单易操作,但是呢,它是先将字符转化为图片纹理,然后渲染至屏幕。所以这种标签不要用于频繁变动的文字,最好是用于静态文字。CCLabelTTF的实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class CC_DLL CCLabelTTF : public CCSprite, public CCLabelProtocol
{
// 创建CCLabelTTF的三种方法
// create(要显示的字符串,字体名称.ttf,字体大小);
// create(要显示的字符串,字体名称.ttf,字体大小,尺寸大小CCSize,水平对其方式)
// create(要显示的字符串,字体名称.ttf,字体大小,尺寸大小CCSize,水平对其方式,垂直对齐方式)
static CCLabelTTF* create(const char *string, const char *fontName, float fontSize);
static CCLabelTTF* create(const char *string, const char *fontName, float fontSize, const CCSize& dimensions, CCTextAlignment hAlignment);
static CCLabelTTF* create(const char *string, const char *fontName, float fontSize, const CCSize& dimensions, CCTextAlignment hAlignment, CCVerticalTextAlignment vAlignment);
// 属性设置
// setString ,
// setHorizontalAlignment , setVerticalAlignment ,
// setDimensions , setFontSize , setFontName
// 显示的字符串内容
void setString(const char *label);
const char* getString(void);
// 水平对齐方式CCTextAlignment::
// kCCTextAlignmentLeft 左对齐
// kCCTextAlignmentCenter 居中,默认方式
// kCCTextAlignmentRight 右对齐
void setHorizontalAlignment(CCTextAlignment alignment);
CCTextAlignment getHorizontalAlignment();
// 垂直对齐方式CCVerticalTextAlignment::
// kCCVerticalTextAlignmentBottom 底部
// kCCVerticalTextAlignmentCenter 中心
// kCCVerticalTextAlignmentTop 顶部,默认方式
void setVerticalAlignment(CCVerticalTextAlignment verticalAlignment);
CCVerticalTextAlignment getVerticalAlignment();
// 尺寸大小
void setDimensions(const CCSize &dim);
CCSize getDimensions();
// 字体大小
void setFontSize(float fontSize);
float getFontSize();
// 字体类型名 如Arial,宋体等
void setFontName(const char *fontName);
const char* getFontName();
// 继承自CCSprite常用函数
setColor(ccColor3B); // 设置颜色
setPosition(CCPoint); // 设置位置
setRotation(float); // 旋转角度,角度制0~360
setOpacity(float); // 设置透明度
setScale(float); // 放缩
setFlipX(float); // 左右翻转
}

代码实现

上面的代码列出了CCLabelTTF的主要方法,下面来看看实际的使用:

1
2
3
CCLabelTTF *ttf = CCLabelTTF::create("Score", "Courier", 20);
ttf->setPosition(ccp(winSize.width / 2, winSize.height / 2));
addChild(ttf);

s

我们将看到一个黑色的窗口中,有着一段白色的文字“Score”。当然,我们还可以使用一些方法设置文字样式:

1
2
3
4
ttf->setFontSize(50);
ttf->setFontName("Courier New");
ttf->setString("Grade");
ttf->setFontFillColor(ccc3(255, 0, 0));

这段文字换成了“Grade”,并且字更大、更圆润。注意一下,setFontFillColor()不一定能在所有平台使用。

CCLabelAtlas

标签介绍

CCLabelAtlas一般常用来显示数字信息,如分数、排名等。因为只是数字所以也犯不上使用CCLabelBMFont加载那么大的文字图像,所以使用这个比较合适。而资源一般来自一张.png图片,或.plist文件。不过它也可以用来显示其他字符,如英文字符。

CCLabelAtlas继承自CCNode,可以使用父类的一些函数。同时,图片中每个字符的大小都是固定的,必须通过缩放来改变大小。

1
2
// 第一个参数为要显示的字符串,第二个参数为图片,第三个参数为字符的长度,第四个为字符的高度,第五个为第一个字符的ASCII码
CCLabelAtlas* lb4 = CCLabelAtlas::create("20140815", "fonts/digit.png", 20, 20, '0');

我们还可以用这几个方法来调整Label

1
2
3
// 内容的文字必须是资源图片中存在的才可以
void setString(const char *label);
const char* getString(void);

我们首先将等宽等高的字符放到一张大图,然后通过要显示的字符的ASCII码去找到相应的字符,并且渲染到屏幕。一次加载之后可以多次使用,比TTF的效率高。但是呢,素材需要依赖美工,显示的内容局限性太大,而且,文字的大小必须用setScale()缩放。

代码实现

首先我们需要一张字体图片:

至于字符的宽和高就需要根据图片的大小来算了,图片的大小可以从属性那一栏看到。这里就设置成24、32。

1
2
3
CCLabelAtlas *atlas = CCLabelAtlas::create("1234", "fonts/Labelatlas.png", 24, 32, '0');
atlas->setPosition(ccp(winSize.width / 2, winSize.height / 2));
addChild(atlas);

没有问题的话就能看到下面的样子:

注意到了没有,其实CCLabelAtlas的锚点默认为(0, 0),这一点一定要记住。另外,假如你的字符串打错了,输入了一些资源图片中没有的字符,比如12abc34。要知道资源图片里面没有abc,那么游戏会发生崩溃吗?游戏并不会崩溃,资源图片中没有的字会被空白所代替。

CCLabelBMFont

标签介绍

CCLabelBMFont文字是最快速最自由的字体类。CCLabelBMFont的父类是CCSpriteBatchNode,特色就是以占用更多内存为代价加快标签的更新,这与其他任何CCSprite类相似。CCLabelBMFont相当于每次改变只改变了图片坐标,而CCLabelTTF要重新渲染。

这个类使用之前,需要添加好字体文件,包括一个图片文件.png和一个字体坐标文件.fnt,这两个文件名称必须一样。可以下载一个fnt编辑工具来自定义字体。

CCLabelBMFont的每个字母或符号都是单独的一个CCSprite精灵,可以使用getChildByTag(i)来获取第i个位置上的字符,来对每个字符单独设置属性、动作等。调整大小只能使用setScale()进行缩放。

1
2
// 第一个参数为要显示的字符串,第二个为.fnt文件的路径
CCLabelBMFont* lb5 = CCLabelBMFont::create("hello", "fonts/bitmapFontTest.fnt");

.fnt文件和.plist文件类似,记录的大图中各个元素的位置信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class CC_DLL CCLabelBMFont : public CCSpriteBatchNode, public CCLabelProtocol, public CCRGBAProtocol
{
// create(要显示的字符串,字体资源名称.fnt)
static CCLabelBMFont * create(const char *str, const char *fntFile);
// 设置字体资源名称.fnt
void setFntFile(const char* fntFile);
const char* getFntFile();
// 设置内容
virtual void setString(const char *newString);
virtual const char* getString(void);
// 设置锚点
virtual void setAnchorPoint(const CCPoint& var);
// 水平对齐方式CCTextAlignment::
// kCCTextAlignmentLeft 左对齐
// kCCTextAlignmentCenter 居中
// kCCTextAlignmentRight 右对齐
virtual void setAlignment(CCTextAlignment alignment);
// 设置宽度
virtual void setWidth(float width);
// 放缩
virtual void setScale(float scale);
virtual void setScaleX(float scaleX);
virtual void setScaleY(float scaleY);
// 设置颜色
virtual void setColor(const ccColor3B& color);
virtual const ccColor3B& getColor(void);
// 透明度0~255,其中255为不透明
virtual void setOpacity(GLubyte opacity);
};

查看CCLabelBMFont类的实现,可以清楚地看到各种可能用到的方法。

代码实现

我们需要一张大图以及记录它位置信息的.fnt文件,然后创建一个CCLabelBMFont标签:

1
2
3
CCLabelBMFont *bm = CCLabelBMFont::create("DARK SOULS", "fonts/bitmapFontTest.fnt");
bm->setPosition(ccp(winSize.width / 2, winSize.height / 2));
addChild(bm);

具体的效果如下:

怎么样,是不是很有感觉呢?CCLabelBMFont中的每一个字符都是一个已经加载到CCSpriteBatchNode中的CCSprite,可以通过接口取出对应的字符。这种实现的方式既灵活也多样化,优化也很好,只不过依赖于美工。

3.x版本的改变

在3.x中,废弃了2.x里的LabelTTFLabelAtlasLabelBMFont三个字体类,取而代之的是全新的字体标签Label。不过其实Label只是将三个类进行了融合,进行统一的管理与渲染,这使得创建字体标签Label的方式更加统一,更加方便。

Label支持四种方式的标签创建。并新增了阴影Shadow、轮廓Outline、发光Glow效果的支持。还支持文字内容的行间距、文字间距、自动换行的设置。

Label

createWithSystemFont()

该方法用于创建系统自带的字体标签,创建的方法如下:

1
2
3
4
5
6
7
8
static Label* createWithSystemFont(
const std::string& text, //字符串内容
const std::string& font, //字体(字体名称、或字体文件)
float fontSize, //字号
const Size& dimensions = Size::ZERO, //label的尺寸大小,默认不设置尺寸
TextHAlignment hAlignment = TextHAlignment::LEFT, //水平对齐方式,默认左对齐::LEFT
TextVAlignment vAlignment = TextVAlignment::TOP //垂直对齐方式,默认顶部 ::TOP
);

比如,我们可以用系统字体“Arial”来创建

1
Label* lb1 = Label::createWithSystemFont("Hello", "Arial", 24);

createWithTTF()

第一种创建方法,是与SystemFont类似,不过必须提供具体的.ttf文件路径,不能够使用系统字体的名称:

1
2
3
Label* lb2 = Label::createWithTTF("Hello", "fonts/Marker Felt.ttf", 24);
lb2->setPosition(ccp(winSize.width / 2, winSize.height / 2));
addChild(lb2);

第二种创建方法,就是使用TTFConfig创建TTF:

1
2
3
4
5
6
static Label* createWithTTF(
const TTFConfig& ttfConfig, //TTFConfig配置
const std::string& text, //字符串内容
TextHAlignment alignment = TextHAlignment::LEFT,
int maxLineWidth = 0 //最大文本行宽,0表示不设置。可用于自动换行只用
);

我们可以这么用:

1
2
3
4
5
6
7
8
9
10
TTFConfig ttfConfig;
ttfConfig.fontFilePath = "fonts/Marker Felt.ttf"; // 必须配置
ttfConfig.fontSize = 12;
ttfConfig.distanceFieldEnabled = false;
ttfConfig.outlineSize = 0;
ttfConfig.glyphs = GlyphCollection::DYNAMIC;
ttfConfig.customGlyphs = nullptr;
// 使用TTFConfig配置,来创建TTF
Label* lb3 = Label::createWithTTF(ttfConfig, "123abc");

createWithCharMap()

CharMap的用法与2.x中的LabelAtlas是一样的,一般用来显示数字。不过它也可以用来显示其他字符,如英文字符。字体文件资源一般来自一张.png图片,或.plist文件。字体大小的缩放同样只能使用setScale()

第一种方法,用.png图片创建,第二种用纹理,第三种用.plist

1
2
3
4
5
6
7
// charMapFile : 字符资源图片png
// itemWidth : 每个字符的宽
// itemHeight : 每个字符的高
// startCharMap : 图片第一个是什么字符
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);

首先用.png

1
2
3
// create 字符图片.png,每个字符宽,高,起始字符
Label* lb4 = Label::createWithCharMap("fonts/digit.png", 20, 20, '0');
lb4->setString("123456"); //设置字符串内容

然后试试纹理

1
2
3
4
5
// 创建图片纹理Texture2D
Texture2D* texture = TextureCache::getInstance()->addImage("fonts/digit.png");
Label* lb5 = Label::createWithCharMap(texture, 20, 20, '0');
lb5->setString("123456"); //设置字符串内容

最后再用.plist

1
2
Label* lb6 = Label::createWithCharMap("fonts/digit.plist");
lb6->setString("123456");

createWithBMFont

BMFont的用法与2.x中的LabelBMFont是一样的。在3.x中,则是使用getLetter(i)来获取单个字符,而不再是getChildByTag(i)

1
2
3
4
5
6
7
static Label* createWithBMFont(
const std::string& bmfontFilePath, // 字体文件.font
const std::string& text, // 内容
const TextHAlignment& alignment = TextHAlignment::LEFT,
int maxLineWidth = 0,
const Vec2& imageOffset = Vec2::ZERO // 字符图片的起始左上角坐标。一般不要设置这个参数,因为坐标的配置均已在.font里完成
);

用法很简单,要注意的是,字符大小只能用setScale()缩放:

1
Label* lb7 = Label::createWithBMFont("bitmapFontTest.fnt", "123abc", TextHAlignment::LEFT);

Label属性与方法

SpriteBatchNode类用于加快渲染,LabelProtocol类用于控制字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
class CC_DLL Label : public SpriteBatchNode, public LabelProtocol
{
/**
* 字体设置
* - setSystemFontName : 字体(字体名字、字体文件)
* - setSystemFontSize : 字体大小
* - setString : 字符串内容
* - setTextColor : 文字内容颜色
**/
// 设置System Font类型的字体(字体名字、字体文件)
// 设置System Font类型的字体大小
// 请不要用于其他Label类型!(TTF、CharMap、BMFont)
virtual void setSystemFontName(const std::string& systemFont);
virtual void setSystemFontSize(float fontSize);
virtual const std::string& getSystemFontName() const { return _systemFont;}
virtual float getSystemFontSize() const { return _systemFontSize;}
// 改变字符串内容并重新渲染
// 注:如果你没有为Label设置TTF/BMFont/CharMap,会产生很大的开销
virtual void setString(const std::string& text) override;
virtual const std::string& getString() const override { return _originalUTF8String; }
// 设置文字颜色,仅支持TTF和System Font
// 注:区别 Node节点的颜色
// Node ::setColor : Color3B
// Label::setTextColor : Color4B
virtual void setTextColor(const Color4B &color);
const Color4B& getTextColor() const { return _textColor; }
/**
* 获取Label的某个字符
* - getLetter
* - 不支持System Font
**/
// 不支持System Font
virtual Sprite* getLetter(int lettetIndex);
/**
* 文字渲染效果
* - Shadow : 阴影
* - Outline : 轮廓,仅支持TTF
* - Glow : 发光,仅支持TTF
**/
// 阴影Shadow(阴影颜色,相对Label的偏移,模糊度)
// 注: 其中blurRadius在3.2中并未实现
virtual void enableShadow(const Color4B& shadowColor = Color4B::BLACK,const Size &offset = Size(2,-2), int blurRadius = 0);
// 轮廓Outline,仅支持TTF(轮廓颜色,轮廓粗细)
virtual void enableOutline(const Color4B& outlineColor,int outlineSize = -1);
// 发光Glow,仅支持TTF
virtual void enableGlow(const Color4B& glowColor);
// 取消阴影/轮廓/发光渲染效果
virtual void disableEffect();
/**
* 对齐方式
* > TextHAlignment : 水平对齐方式
* - TextHAlignment:LEFT : 左对齐
* - TextHAlignment:CENTER : 居中对齐,默认
* - TextHAlignment:RIGHT : 右对齐
* > TextVAlignment : 垂直对齐方式
* - TextVAlignment::TOP : 顶部,默认
* - TextVAlignment::CENTER : 中心
* - TextVAlignment::BOTTOM : 底部
**/
// 设置对齐方式
void setAlignment(TextHAlignment hAlignment) { setAlignment(hAlignment,_vAlignment);}
void setAlignment(TextHAlignment hAlignment,TextVAlignment vAlignment);
TextHAlignment getTextAlignment() const { return _hAlignment;}
// 设置水平对齐方式
void setHorizontalAlignment(TextHAlignment hAlignment) { setAlignment(hAlignment,_vAlignment); }
TextHAlignment getHorizontalAlignment() const { return _hAlignment; }
// 设置垂直对齐方式
void setVerticalAlignment(TextVAlignment vAlignment) { setAlignment(_hAlignment,vAlignment); }
TextVAlignment getVerticalAlignment() const { return _vAlignment; }
/**
* Label尺寸大小
* - setLineBreakWithoutSpace : 开启自动换行功能
* - setMaxLineWidth : 文字内容的最大行宽
* - setWidth : Label尺寸大小,宽
* - setHeight : Label尺寸大小,高
* - setDimensions : Label尺寸大小
**/
// 是否开启自动换行功能
void setLineBreakWithoutSpace(bool breakWithoutSpace);
// 最大行宽,内容超过MaxLineWidth,就会自动换行
// 前提条件: 仅在width==0时,起作用。
// > width == 0;
// > setMaxLineWidth(lineWidth);
// > setLineBreakWithoutSpace(true);
// 它的效果与下面是类似的.
// > setWidth(lineWidth);
// > setLineBreakWithoutSpace(true);
// 只是width==0时,就无法设置文本的对齐方式了.
void setMaxLineWidth(unsigned int maxLineWidth);
unsigned int getMaxLineWidth() { return _maxLineWidth;}
// 设置Label的尺寸大小
// 可以理解为Label的文本框大小
// 当setLineBreakWithoutSpace(true)时,内容超过width,会自动换行
// 并且内容支持文本的对齐方式
// 注:设置尺寸大小,使用的是setDimensions,而不是setContentSize !
void setWidth(unsigned int width) { setDimensions(width,_labelHeight); }
void setHeight(unsigned int height){ setDimensions(_labelWidth,height); }
void setDimensions(unsigned int width,unsigned int height);
unsigned int getWidth() const { return _labelWidth; }
unsigned int getHeight() const { return _labelHeight; }
const Size& getDimensions() const{ return _labelDimensions; }
/**
* v3.2 新增
* - setLineHeight : 设置行间距
* - setAdditionalKerning : 设置文字间距
* - getStringLength : 字符串内容长度
*/
// 设置行间距,不支持system font
void setLineHeight(float height);
float getLineHeight() const;
// 设置文字间距,不支持system font
void setAdditionalKerning(float space);
float getAdditionalKerning() const;
// 获取Label的字符串内容长度
int getStringLength() const;
/**
* 重写Node父类的方法
* - setBlendFunc : 混合模式
* - setScale : 放缩字体大小
* - addChild : 添加子节点
* - getDescription : 显示Label的描述
**/
// 设置颜色混合模式
virtual void setBlendFunc(const BlendFunc &blendFunc) override;
// 放缩字体大小(一般用于CharMap、BMFont)
virtual void setScale(float scale) override;
virtual void setScaleX(float scaleX) override;
virtual void setScaleY(float scaleY) override;
virtual float getScaleX() const override;
virtual float getScaleY() const override;
// 添加子节点
virtual void addChild(Node * child, int zOrder=0, int tag=0) override;
virtual void sortAllChildren() override;
// Label描述
virtual std::string getDescription() const override;
};

文字渲染效果

3.x中支持三种渲染效果:

  • Shadow阴影
  • Outline轮廓
  • Glow发光

这里我们简单的演示一下:

1
2
3
4
5
6
7
8
9
Label* lb3 = Label::createWithTTF("123abc", "fonts/arial.ttf", 50);
lb3->setPosition(winSize.width / 2, winSize.height / 2);
this->addChild(lb3);
//lb3->enableShadow(Color4B::GREEN, Size(10, 10)); // 阴影
//lb3->enableOutline(Color4B::RED, 3); // 轮廓
//lb3->enableGlow(Color4B::GREEN); // 发光
//lb3->disableEffect(); // 取消渲染效果

实际效果大概就是下面这样:



发光的效果可能不太明显,不过字体确实发出了绿光。

对齐方式

水平对齐:

  • TextHAlignment:LEFT,左对齐
  • TextHAlignment:CENTER,中间对齐,默认
  • TextHAlignment:RIGHT,右对齐

垂直对齐:

  • TextVAlignment::TOP,顶部对齐,默认
  • TextVAlignment::CENTER,中间对齐
  • TextVAlignment::BOTTOM,底部对齐

注意,这两种对齐只有在使用setDimensions(width, height)设置了Label的尺寸大小后,才能够使用。

自动换行

我们可以使用‘\n’来控制换行,但是呢,我们同样可以使用Cocos自带的自动换行。这里我们调用Label的子方法来开启自动换行:

1
2
lb->setLineBreakWithoutSpace(true);
lb->setMaxLineWidth(120); // 最大宽度120

上面简单的设置了每行的最大宽度,但是呢,使用这种方法必须是没有设置标签的尺寸。如果你觉得需要规范文本大小,你也可以这么做:

1
2
lb->setLineBreakWithoutSpace(true);
lb->setWidth(80); // 设置Label尺寸宽80

但是这么用的话,我们就无法使用setMaxLineWidth()来设置了。

文字间距

3.2版本后,可以调整文字的行间距和文字间距:

1
2
lb->setLineHeight(80); // 设置行间距
lb->setAdditionalKerning(10); // 设置额外文字间距

注意,SystemFont不支持这种用法。

单独设置某个字符

我们可以使用下面的方法获取某个字符:

  • lb->getStringLength(),获取字符串长度
  • lb->getLetter(i),获取第i个位置上的字符
1
Sprite* letter1 = lb->getLetter(1);

注意,SystemFont不支持这种用法。