转载:http://blog.csdn.net/zhanglongit/article/details/8451641
相关几个重要的类的继承关系如下
1.所有文本框必须实现CCLabelProtocol接口
2.CCLableTTF比另外两个文本框渲染慢
TTF(TrueTypeFont)是一种字库名称,是Apple公司和Microsoft公司共同推出的字体文件格式,随着windows的流行,已经变成最常用的一种字体文件表示方式。
OK, 看下它的使用方法
CCLabelTTF *label = CCLabelTTF::labelWithString("the string","Marker Felt",21);
3.CCLabelBMFont中每个文字相当于一个CCSprite,可以旋转,移动,改变尺寸等
CCLabelBMFont
CCLabelIBMFont *label = CCLabelIBMFont::labelWithString("the string","font-hd.png");
this->addChild(label);
label->setPosition(ccp(100,100));
label->setString("change string");
下面是font-hd.png文件的截图
font-hd.fnt文件定义了 图像文件的名称,以及每个字符对应的位置信息。
4.CCLabelAtlas
如果你用cocos2d-x项目模板创建过项目,那么你已经看过它的效果了,就是左下角显示帧率的数字。
因为帧率一直在变,使用CCLabelTTF的话效率太低,因为只是数字所以也犯不上使用 CCLabelBMFont 加载那么大的文字图像,所以使用这个比较合适。
CCLabelAtlas *label = CCLabelAtlas::labelWithString("12","fps_images.png",12,18,".");
this->addChild(label);
label->setPosition(ccp(100,100));
label->setString("34");
5.下面具体分析一下画字的原理(参考一篇博客)
图字,顾名思义,利用图片做为纹理来显示的文字。当下流行的跨平台2D引擎Cocos2d-x和LibGdx也都有对于图字的应用支持,今天我就来为大家讲一讲图字。
首先要介绍一下,图字是怎么来的?其实这个很早很早了,记得80后在95年开始玩DOS下的仙剑奇侠传的时候,那些令人难忘的中文对话吧!DOS下做游戏,使用的是C语言,不要说写字了,很多复杂的操作甚至涉及驱动。那时候绘图就是利用将图片中的像素取出来后绘制在屏幕上,所以处理游戏中的中文,就只有把这些文字的像素预先写到BMP或二进制文件中,然后读取出来再设置屏幕像素以实现。后来进入DDRAW的时代,可以使用WINDOWS系统中的字库来写字了。把DDRAW的后台表面进行LOCK,取出其DC,然后用GDI将文字写到其DC上,这种做法后面也延续了很久,但GDI进行TextOut的效率非常慢,你要是想像梦幻西游一样满屏写了,那得卡死,解决方案是什么?还是图字。专业的游戏开发者会将所用到的字都预处理生成到一张图片中,通过一个编码与纹理UV对应文件来进行纹理UV的获取后做为顶点的UV值然后进行绘制,有也的在每一帧中实时的将需要的字使用DDRAW写字的方法绘制到相应的纹理上然后使用文字编码与纹理UV对应信息来进行绘制,这样效率就提高很多了。目前比较流行的做法是使用一张png图片来存储用到的文字。一个.fnt文件来存储文字图片说明信息。Cocos2d-x和LibGdx中都集成了相关的图字处理类。在世界范围内,也有很多游戏使用了这个方案。在游戏汉化界,了解和掌握图字的原理和修改方法也是很重要的一项工作
我们以Cocos2d-x的tests工程中的LabelTest中的最后一个Label显示“中国”为例来分析一下。
打开Cocos2d-x所在目录下的tests\Resources\fonts目录,找到bitmapFontChinese.png(文字贴图文件)和bitmapFontChinese.fnt(文字图片说明信息文件)
先打开png,我们可以看到它是512×512大小,上面由12行,14列个文字组成。包括有一些汉字,常用字符,数字和字母。它的每个字都是由青色到蓝色的向下渐变。
再用UEdit或记事本打开bitmapFontChinese.fnt,可以看到它的构成,我在这里讲一下。
第一行是对字体的介绍。
1 |
info face="华康海报体W12(P)" size=32 bold=0italic=0 charset="" unicode=0stretchH=100smooth=1 aa=1 padding=0,0 spacing=1,1
|
解释:
face=”华康海报体W12(P)”:字体为”华康海报体W12(P)”,
size=32:大小为32像素
bold=0 :不加粗
italic=0:不使用斜体
charset=”":charset是编码字符集,这里没有填写值即使用默认,
unicode=0:不使用Unicode
stretchH=100:纵向缩放百分比
smooth=1 :开启平滑
aa=1:开启抗锯齿
padding=0,0:内边距,文字与边框的空隙。
spacing=1,1 :外边距,就是相临边缘的距离。
第二行是对应所有字贴图的公共信息
1 |
common lineHeight=37 base=28 scaleW=512 scaleH=512pages=1 packed=0
|
解释:
lineHeight=37:行高,如果遇到换行符时,绘制字的位置坐标的Y值在换行后增加的像素值。
base=28 :字的基本大小
scaleW=512 :图片大小
scaleH=512:图片大小
pages=1 :此种字体共用到几张图。
packed=0:图片不压缩
第三行是对应当前字贴图的信息
//第一页,文件名称是”bitmapFontChinese.png”
page id=0 file=”bitmapFontChinese.png”
chars count=204
第五行起把当前贴图中所用到的所有文字的编码以及对应在图片上的矩形位置,偏移等列出来
第一个字符编码为32,也就是空格,位置为0,宽高为0,绘制到屏幕的相应位置时,像素偏移(0,28),绘制完后相应位置的x往后移15像素再画下一个字符,字的图块在第1页上
char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=28 xadvance=15 page=0 chnl=0
第一个字符编码为汉字”象”,宽为33,高为36,绘制到屏幕的相应位置时,像素偏移(0,-1),绘制完后相应位置的x往后移36像素再画下一个字,字的图块在第1页上
char id=35937 x=0 y=0 width=33 height=36 xoffset=0 yoffset=-1 xadvance=36 page=0 chnl=0
char id=26696 x=33 y=0 width=35 height=36 xoffset=-1 yoffset=-1 xadvance=36 page=0 chnl=0
char id=26071 x=68 y=0 width=35 height=36 xoffset=-1 yoffset=-1 xadvance=36 page=0 chnl=0
…
再后面是描述两个字在进行组合绘制时字距调整的相关信息,这里没有要进行间距调整的字组合所以为设-1。对于字组合间距调整可以看此示例图:
kernings count=-1
这个数字代表参与字组合间距调整的字的数量。
如果kernings count大于零,后面会有类似这样的描述:
kerning first=102 second=41 amount=2
也就是’f’与’)’进行组合显示’f)’时,’)’向右移2像素防止粘在一起。
通过上面这些信息,引擎可以通过编码找到相应的文字并取出对应的纹理块。
//Cocos2d-x中LabelBMFontChinese
下面我们来分析一下Cocos2d-x的tests工程中的LabelTest中的最后一个Label,它的类名为CCLabelBMFont.转到其类定义文件CCLabelBMFont.h
1 |
classCC_DLL CCLabelBMFont
:
publicCCSpriteBatchNode,publicCCLabelProtocol,255)">publicCCRGBAProtocol
|
可以看到其直接派生于三个类,分别是
CCSpriteBatchNode :精灵批次管理类,用于将使用一张图的多个精灵在设置一次纹理的批次里进行绘制,提高渲染的效率。
CCLabelProtocol :文字字串类
CCRGBAProtocol:颜色调节接口类
由简入深,我们先来看一下CCRGBAProtocol,打开CCProtocols.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
classCC_DLL CCRGBAProtocol
{ public : //设置颜色 virtual voidsetColor ( constccColor3B &color ) = 0 ; //取得颜色 &getColor void //返回透明度 virtualGLubyte getOpacity //设置透明度 voidsetOpacity (GLubyte opacity //设置是否使用Alpha值设置RGB,如果 voidsetIsOpacityModifyRGB boolbValue //取得是否使用Alpha值设置RGB boolgetIsOpacityModifyRGB ; } ; |
可以看到CCRGBAProtocol类是个纯虚类,只是定义了一些设置获取颜色信息的接口函数。
继续看CCLabelProtocal,明显的,它也是纯虚类,做为存储字符串的接口使用:
1 2 3 4 5 6 7 8 9 |
最后来分析CCSpriteBatchNode类。它由CCNodet 和 CCTextureProtocal两个类派生而来,CCNode是基础结点类,用于将引擎中所有具有逻辑顺序和父子关系的类组织起来,基于CCNode派生的类均可以互相挂接。CCNode不是本章要详细介绍的内容,就不再详细分析了,看一下CCTextureProtocol,这是一个纹理使用接口类:
1 2 3 4 5 6 7 8 9 |
classCC_DLL CCTextureProtocol
publicCCBlendProtocol
// 返回所使用的2D纹理 virtualCCTexture2D *getTexture // 设置使用的2D纹理,并为纹理的使用计数器加1操作 voidsetTexture (CCTexture2D *texture ; |
很简单,只有两个函数对纹理进行设置和获取,它派生于CCBlendProtocal,这是一个Alpha混合系数设置接口类,用于在开启Alpha混合状态后对Alpha混合的系数进行设置。再来看一下CCBlendProtocal,这是一个混合状态设置接口类:
1 2 3 4 5 6 7 8 9 |
classCC_DLL CCBlendProtocol
// 为纹理设置使用的混合状态 voidsetBlendFunc (ccBlendFunc blendFunc // 返回为纹理设置的混合状态 virtualccBlendFunc getBlendFunc ; |
返回到类CCSpriteBatchNode的定义。我们再来分析CCSpriteBatchNode。之前说了CCSpriteBatchNode是精灵批次管理类,用于将使用一张图的多个精灵在设置一次纹理的批次里进行绘制,提高渲染的效率。既然多个精灵使用一张图,则需要将多个小图块合并在一张图上,这样只要设置使用大图做为纹理,将使用各小图块做为纹理贴图的精灵设置好顶点与UV等数据,就可以绘制出这些精灵了。Cocos2d-x提供了一个类CCTextureAtlas对使用图块的这些精灵所使用的顶点缓冲区进行管理。为了更好的理解CCSpriteBatchNode,我们看一下它的定义和实现:
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 |
@H_403_859@#ifndef __CCTEXTURE_ATLAS_H__
#define __CCTEXTURE_ATLAS_H__ //用到的头文件 #include <string> #include "ccTypes.h" #include "CCObject.h" #include "ccConfig.h" //使用Cocos2d命名空间 namespace cocos2d classCCTexture2D ; //CCTextureAtlas由CCObject派生而来 classCC_DLL CCTextureAtlas publicCCObject protected //使用此大图中的图块的精灵对应的三角形索引数组的指针 GLushort *m_pIndices ; #if CC_USES_VBO //如果使用Vertex Buffer Object(VBO:使用显存而非内存存储顶点缓冲数据,大大提高效率),建立VBO句柄数组,第一个元素存顶点数组的句柄,第二个元素存索引数组句柄 GLuint m_pBuffersVBO [ 2 ] ; //标记是否更新需要更新的图块信息。当你新加入了图块或者修改了图块,需要设置为true。 bool m_bDirty #endif // CC_USES_VBO // CC_PROPERTY_READONLY宏为类定义变量及增加相应的get函数。 //当前使用图块的数量 CC_PROPERTY_READONLY unsigned int,m_uTotalQuads,TotalQuads ) //存储图块信息的数组容量 CC_PROPERTY_READONLY //设置所使用的大图纹理 CC_PROPERTY *,m_pTexture,Texture //使用此大图的图块的所有精灵的顶点缓冲信息数组 CC_PROPERTY (ccV3F_C4B_T2F_Quad ) //构造 CCTextureAtlas //析构 virtual~CCTextureAtlas //描述 *description //静态函数:从文件中创建纹理,并初始化图块容量 staticCCTextureAtlas *textureAtlasWithFile *file,255)">intcapacity //同上,只是非静态函数。作者提示不能重复调用,否则会造成内存泄漏。 boolinitWithFile //静态函数:从贴图中创建纹理,并初始化图块容量 *textureAtlasWithTexture *texture,255)">boolinitWithTexture //通过索引值找到对应的图块顶点缓冲数据并用新数据修改它,由CCSprite实例对象在变换顶点信息时调用。 voidupdateQuad *quad,255)">intindex //通过索引值找到对应的图块顶点缓冲数据,并在其之前插入一个新的图块。 voidinsertQuad //通过索引值找到对应的图块顶点缓冲数据,并把它插入另一个图块之前。 voidinsertQuadFromIndex intfromIndex,255)">intnewIndex //移除指定位置的图块顶点缓冲数据. voidremoveQuadAtIndex //清空所有的图块顶点缓冲数据。 voidremoveAllQuads //重新设置图块顶点缓冲数组的容量 boolresizeCapacity intn //绘制指定的图块顶点缓冲 voiddrawNumberOfQuads //绘制从指定的图块起后面的N个图块 intn,255)">intstart //绘制所有的图块顶点缓冲 voiddrawQuads private //初始化索引缓冲数据 voidinitIndices } //namespace cocos2d #endif //__CCTEXTURE_ATLAS_H__ |
再看CPP:
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 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
#include "CCTextureAtlas.h"
#include "CCTextureCache.h" #include "ccMacros.h" // 纹理头文件 #include "CCTexture2D.h" #include <stdlib.h> { //构造,初始化成员变量 CCTextureAtlas :: CCTextureAtlas ) :m_pIndices NULL ) #if CC_USES_VBO ,m_bDirty false #endif ,m_pTexture ) ,m_pQuads ) { } //析构,释放所用的内存 CCTextureAtlas ::~CCTextureAtlas // CCLOGINFO("cocos2d: deallocing CCTextureAtlas."); CC_SAFE_FREE (m_pQuads ) CC_SAFE_FREE (m_pIndices ) //释放缓冲区对象 glDeleteBuffers 2,m_pBuffersVBO #endif // CC_USES_VBO CC_SAFE_RELEASE (m_pTexture //实现通过宏CC_PROPERTY_READONLY声明的函数 //取得当前使用的图块的数量 intCCTextureAtlas getTotalQuads { returnm_uTotalQuads //取得图块集的容量 getCapacity returnm_uCapacity //取得大纹理 CCTexture2D *CCTextureAtlas getTexture returnm_pTexture //设置大纹理 voidCCTextureAtlas setTexture *var { CC_SAFE_RETAIN (var ; CC_SAFE_RELEASE ; m_pTexture =var //取得使用此大图的图块的所有精灵的顶点缓冲信息数组 ccV3F_C4B_T2F_Quad getQuads returnm_pQuads //设置使用此大图的图块的所有精灵的顶点缓冲信息数组 setQuads { m_pQuads } //静态函数:从文件中创建纹理,并初始化图块容量 CCTextureAtlas textureAtlasWithFile { //使用new来实例化一个CCTextureAtlas对象 CCTextureAtlas *pTextureAtlas newCCTextureAtlas //调用成员函数进行初始化 if (pTextureAtlas &&pTextureAtlas - >initWithFile (file,capacity { pTextureAtlas >autorelease ; returnpTextureAtlas ; } //如果失败,释放后返回NULL CC_SAFE_DELETE return //静态函数:从贴图中创建纹理,并初始化图块容量 CCTextureAtlas textureAtlasWithTexture >initWithTexture (texture,102)">//非静态函数,从文件中创建纹理,并初始化图块容量 boolCCTextureAtlas initWithFile // 由纹理管理器加载一个图片文件,返回生成的纹理 CCTexture2D =CCTextureCache sharedTextureCache >addImage (file //判断生成纹理是否有效 (texture { //如果成功,使用纹理进行初始化 returninitWithTexture } else //不成功打印错误日志并返回NULL CCLOG ( "cocos2d: Could not open file: %s",file delete this ; } //非静态函数,设置纹理,并初始化图块容量 initWithTexture //纹理有效性判断,防止重复调用 CCAssert ! NULL,"texture should not be null" //设置图块容量 m_uCapacity =capacity ; m_uTotalQuads // 设置纹理 this >m_pTexture =texture ; CC_SAFE_RETAIN // 判断是否重复调用 CCAssert == &&m_pIndices "" //申请容量大小的的顶点缓冲信息数组 m_pQuads * calloc sizeof *m_uCapacity,221)">1 //申请容量大小的索引缓冲数组 m_pIndices (GLushort *m_uCapacity 6,102)">//如果失败,做相应处理 &&m_uCapacity > //CCLOG("cocos2d: CCTextureAtlas: not enough memory"); CC_SAFE_FREE ) CC_SAFE_FREE ) CC_SAFE_RELEASE_NULL //初始化缓冲区对象 #if CC_USES_VBO glGenBuffers &m_pBuffersVBO ; m_bDirty true #endif // CC_USES_VBO //初始化索引缓冲 this >initIndices ; //取得描述 description *ret new 100 sprintf (ret,0)">"<CCTextureAtlas | totalQuads = %u>",m_uTotalQuads returnret //初始化索引缓冲 initIndices //如果容量为0直接返回 (m_uCapacity ) //按照顶点的顺序和使用的三角形渲染排列方式为索引缓冲填充数据。 for inti ;i <m_uCapacity ++ { #if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP m_pIndices [i 6 + =i 4 ; m_pIndices ; m_pIndices 3 5 #else m_pIndices (i ; // inverted index. issue #179 m_pIndices ; // m_pIndices[i*6+3] = i*4+2; // m_pIndices[i*6+4] = i*4+3; // m_pIndices[i*6+5] = i*4+1; #endif } //指定m_pBuffersVBO[0]为顶点缓冲区,并激活缓冲区 glBindBuffer (GL_ARRAY_BUFFER,102)">//绑定完成后为其分配内存 glBufferData //指定m_pBuffersVBO[1]为索引缓冲区,并激活缓冲区 glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,m_pIndices,GL_STATIC_DRAW //取消绑定 glBindBuffer ; glBindBuffer #endif // CC_USES_VBO //通过索引值找到对应图块的顶点缓冲并用新数据修改它 updateQuad //有效性判断 CCAssert (index >= &&index <m_uCapacity,0)">"updateQuadWithTexture: Invalid index" //如果index大于现有的数量则更新数量 m_uTotalQuads =max 1,102)">//修改对应的数据值 m_pQuads [index *quad ; //需要更新 #if CC_USES_VBO m_bDirty #endif //通过索引值找到对应图块的顶点缓冲,并在其位置之前插入一个新的图块。 insertQuad "insertQuadWithTexture: Invalid index" //数量增加 m_uTotalQuads ; CCAssert (m_uTotalQuads <=m_uCapacity,0)">"invalid totalQuads" //先将索引位置之后的数据整体后移一个位置,再用新数据填充索引位置的数据。实现插入操作。 intremaining -index ; (remaining // texture coordinates memmove &m_pQuads ],64)">*remaining ; } m_pQuads //设置需要更新m_pBuffersVBO中的VBO数组数据。 //通过索引值找到对应图块的顶点缓冲,并把它插入另一个图块之前。 insertQuadFromIndex intoldIndex,0)">(newIndex &&newIndex <m_uTotalQuads,0)">"insertQuadFromIndex:atIndex: Invalid index" (oldIndex &&oldIndex //两个索引相同直接返回即可 ==newIndex //计算要移动的图块数量 inthowMany -newIndex ? -oldIndex intdst =oldIndex intsrc >newIndex { dst =newIndex ; src } // 开始进行移动 ccV3F_C4B_T2F_Quad quadsBackup =m_pQuads [oldIndex [dst [src *howMany //更新新索引位置的数据 m_pQuads [newIndex =quadsBackup //移除指定位置的图块顶点缓冲 removeQuadAtIndex "removeQuadAtIndex: Invalid index" //将索引图块后的所有图块向前移1个位置即可 // last object doesn't need to be moved //数量减1 m_uTotalQuads -- //移除所有的顶点缓冲数据 removeAllQuads //数量直接置0,这是最快的方式 m_uTotalQuads // 重新设置图块顶点缓冲数组的容量 resizeCapacity intnewCapacity //如果等于原来的容量直接返回 (newCapacity ==m_uCapacity //确保当前绘制的精灵数量最大不能超过容量 m_uTotalQuads =min (m_uTotalQuads,newCapacity //更新容量 m_uCapacity =newCapacity ; //定义指针存放要申请的图块信息与索引数组的内存地址 *tmpQuads *tmpIndices //为图块的顶点缓冲数组申请内存,注意:如果已占有内存则直接在原内存地址上进行内存长度调整 ) tmpQuads else tmpQuads realloc (m_pQuads,102)">//为图块的索引缓冲数组申请内存,如果已占有内存则直接在原内存地址上进行内存长度调整 ) tmpIndices else tmpIndices (m_pIndices,102)">//如果内存申请失败的处理 (tmpQuads &&tmpIndices //CCLOG("cocos2d: CCTextureAtlas: not enough memory"); ) free else (tmpIndices ; m_pQuads ; m_uCapacity =m_uTotalQuads //如果成功,则将内存地址赋给相应成员指针变量 m_pQuads )tmpQuads ; m_pIndices )tmpIndices //释放顶点缓冲对象并重新创建和进行绑定 #if CC_USES_VBO glDeleteBuffers // initial binding glGenBuffers #endif // CC_USES_VBO //设置需要更新m_pBuffersVBO中的VBO数组数据。上面已经设了,这里重复可以不要。 #endif //绘制所有的图块顶点缓冲数据 drawQuads { this >drawNumberOfQuads //绘制指定的图块顶点缓冲数据 drawNumberOfQuads (n,102)">//绘制从指定的图块顶点缓冲数据起后面的N个图块顶点缓冲数据 // Default GL states: GL_TEXTURE_2D,GL_VERTEX_ARRAY,GL_COLOR_ARRAY,GL_TEXTURE_COORD_ARRAY // Needed states: GL_TEXTURE_2D,102)">// Unneeded states: - // 如果数量为零直接返回。 ==n //设置使用纹理 glBindTexture (GL_TEXTURE_2D,128)">>getName ; #define kQuadSize sizeof(m_pQuads[0].bl) //如果使用VBO所进行的渲染设置 //绑定完成后为其分配内存 #if CC_ENABLE_CACHE_TEXTTURE_DATA glBufferData #endif //在绘制时如果遇到需要更新标记,则重新将顶点缓冲数据更新到绑定的对象上。 (m_bDirty { glBufferSubData *start,64)">*n,0)">[start ; m_bDirty } // 对顶点缓冲中的顶点格式进行解释,让显卡知道顶点格式的构成。 // 顶点缓冲中哪个是位置数据 glVertexPointer 3,GL_FLOAT,kQuadSize,0)">(GLvoid offsetof (ccV3F_C4B_T2F,vertices //顶点缓冲中哪个是颜色数据 glColorPointer 4,GL_UNSIGNED_BYTE,colors //顶点缓冲中哪个是纹理坐标数据 glTexCoordPointer //指定m_pBuffersVBO[1]为索引缓冲区,并激活缓冲区 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_pBuffersVBO[1]); #endif //按照相应的三角形排列进行渲染 #if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP glDrawElements (GL_TRIANGLE_STRIP,0)">(GLsizei )n (start ; #else glDrawElements (GL_TRIANGLES,0)">#endif // CC_USES_VBO //从显存上卸载绑定的数据 //停止使用缓冲区 glBindBuffer #else // ! CC_USES_VBO //如果不使用VBO所进行的渲染设置 intoffset int )m_pQuads //设置OpenGL渲染使用的顶点数据 intdiff ; glVertexPointer (offset +diff //设置OpenGL渲染使用的颜色数据 diff ; glColorPointer //设置OpenGL渲染使用的纹理坐标数据 diff ; glTexCoordPointer ; +start #endif } //namespace cocos2d |
清楚了CCTextureAtlas,现在回过头再来看CCSpriteBatchNode。
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 |
classCC_DLL CCSpriteBatchNode
publicCCNode,255)">publicCCTextureProtocol
: //析构 ~CCSpriteBatchNode ; // 取得纹理图块顶点缓冲管理器。 inlineCCTextureAtlas *getTextureAtlas returnm_pobTextureAtlas ; } //设置纹理图块顶点缓冲管理器 inline voidsetTextureAtlas (CCTextureAtlas *textureAtlas { //如果当前使用的纹理图块顶点缓冲管理器与要设置的纹理图块顶点缓冲管理器不同,先释放原顶点缓冲管理器,再将当前使用的顶点缓冲管理器指针指向要设置顶点缓冲管理器。 (textureAtlas =m_pobTextureAtlas { CC_SAFE_RETAIN ; CC_SAFE_RELEASE (m_pobTextureAtlas ; m_pobTextureAtlas =textureAtlas ; } //取得存放所有使用此图块集的CCSprite指针数组 inlineCCArray *getDescendants returnm_pobDescendants } //静态函数:通过纹理指针按照默认的图块数量29创建一个CCSpriteBatch实例对象。注意:如果游戏运行中图块数量超过这个数值,则数量递增33%以满足需要 staticCCSpriteBatchNode *batchNodeWithTexture *tex //静态函数:通过纹理指针按照设定的图块数量创建一个CCSpriteBatch实例对象。 *tex,102)">//静态函数:通过图片名称按照默认的图块数量29创建一个CCSpriteBatch实例对象。 *batchNodeWithFile *fileImage //静态函数:通过图片名称按照设定的图块数量创建一个CCSpriteBatch实例对象。 *fileImage,102)">//通过纹理指针和图块数量进行初始化。 ; //通过图片名称和图块数量进行初始化。 ; //扩容,递增1/3的图块数量 voidincreaseAtlasCapacity //通过索引移除一个子结点,参数doCleanUp决定移除的同时是否对其进行释放。 voidremoveChildAtIndex intindex,255)">booldoCleanup //将一个指定的CCSprite指针插入到子节点指针数组的指定位置 voidinsertChild (CCSprite *child,102)">//移除一个指定的CCSprite指针 voidremoveSpriteFromAtlas *sprite //重新构建指定的CCSprite指针下的所有子结点的索引 intrebuildIndexInOrder *parent,102)">//取得指定CCSprite的所有节点的最大图块索引 inthighestAtlasIndexInChild //取得指定CCSprite的所有节点的最小图块索引 intlowestAtlasIndexInChild //取得指定CCSprite的Z顺序之上或之下的最近的图块索引 intatlasIndexForChild *sprite,255)">intz // 实现CCTextureProtocol的接口函数 // 取得纹理 // 设置纹理 //为纹理设置使用的混合状态 //取得混合状态 //重载CCNode的相关函数 //每一帧要被调用的函数 voidvisit //将一个CCNode指针做为自已的子结点 voidaddChild (CCNode *child //将一个CCNode指针以指定的Z顺序做为自已的子结点 intzOrder //将一个CCNode指针以指定的Z顺序并附带一个参数值做为自已的子结点 intzOrder,255)">inttag //将一个子结点重新设置Z顺序 voidreorderChild //将一个子结点删除,并根所参数决定是否释放元素 voidremoveChild boolcleanup //将所有的子结点移除,并根所参数决定是否释放元素 voidremoveAllChildrenWithCleanup //绘制函数 voiddraw : //从精灵数据中在图块管理器中插入一个新的图块,注意:并不将精灵放入子结点。 void addQuadFromSprite(CCSprite *sprite,unsigned int index); //在子结点数组指定位置插入一个新的精灵。注意:并不新建图块。 CCSpriteBatchNode *addSpriteWithoutQuad intz,255)">intaTag //更新混合状态 voidupdateBlendFunc //使用的纹理图块顶点缓冲管理器 CCTextureAtlas *m_pobTextureAtlas //混合状态 ccBlendFunc m_blendFunc //指向存放所有使用此纹理中的图块的CCSprite指针数组的指针 CCArray *m_pobDescendants ; |
再看CPP:
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 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 |
//加入用到的头文件
#include "CCSpriteBatchNode.h" #include "ccConfig.h" #include "CCSprite.h" #include "effects/CCGrid.h" #include "CCDrawingPrimitives.h" #include "CCPointExtension.h" //使用cocos2d命名空间 namespacecocos2d //定义整型常量defaultCapacity做为默认创建的图块数量 intdefaultCapacity 29 ; //静态函数:通过纹理指针按照默认的图块数量29创建一个CCSpriteBatch实例对象。 CCSpriteBatchNode batchNodeWithTexture //使用new创建一个CCSpriteBatchNode实例对象。 CCSpriteBatchNode *batchNode newCCSpriteBatchNode //使用纹理指针和默认图块数量对CCSpriteBatchNode实例对象进行初始化。 batchNode (tex,defaultCapacity //设置其由内存管理器进行内存释放。 batchNode //返回新创建的CCSpriteBatchNode实例对象 returnbatchNode //静态函数:通过纹理指针按照设定的图块数量创建一个CCSpriteBatch实例对象。 CCSpriteBatchNode *CCSpriteBatchNode //同上一函数 CCSpriteBatchNode ; batchNode //静态函数:通过图片名称按照设定的图块数量创建一个CCSpriteBatch实例对象。 CCSpriteBatchNode batchNodeWithFile //这里参数1改为图片名称 batchNode (fileImage,102)">//静态函数:通过图片名称按照默认的图块数量29创建一个CCSpriteBatch实例对象 CCSpriteBatchNode //同上 CCSpriteBatchNode //通过纹理指针和图块数量进行初始化。注意:这个函数才是真正进行初始化的实现过程。 boolCCSpriteBatchNode //设置混合系数,源混合系数为CC_BLEND_SRC,目标混合系数为CC_BLEND_DST,则图像绘制时按照纹理或色彩的Alpha值与背景进行混合。 m_blendFunc. src =CC_BLEND_SRC ; m_blendFunc. dst =CC_BLEND_DST //创建一个图片集管理器 m_pobTextureAtlas //将纹理和图块数量做为参数初始化图片集,这里可知图块集还是依靠CCTextureAtlas类。 m_pobTextureAtlas //更新混合状态 updateBlendFunc // 新建一个CCArray实例,将m_pChildren指向它 m_pChildren =CCArray array //新建一个存放所有使用此图块集的CCSprite指针数组,将m_pobDescendants指向它 m_pobDescendants //分别进行引用计数加1操作。 m_pChildren >retain ; m_pobDescendants //通过纹理文件名和图块数量进行初始化。 //使用纹理管理器加载一个图片,生成的纹理返回给变量pTexture2D CCTexture2D *pTexture2D (fileImage //以变量pTexture2D为参数调用上一个函数进行初始化 (pTexture2D,102)">//析构 CCSpriteBatchNode ::~CCSpriteBatchNode //释放图块集 CC_SAFE_RELEASE ; CC_SAFE_RELEASE (m_pobDescendants // 是基类CCNode虚函数,是每帧会被调用到的函数。 voidCCSpriteBatchNode visit //如果不显示,则直接返回。 !m_bIsVisible { //矩阵压栈,保存渲染此结点前的所有OpenGL所需矩阵的值 glPushMatrix //如果 (m_pGrid &&m_pGrid >isActive { m_pGrid >beforeDraw ; transformAncestors //矩阵变量 transform //基类CCNode虚函数,用于实现当前CCNode的绘制。 draw // >afterDraw //矩阵出栈。恢复渲染此结点前的所有OpenGL所需矩阵的值 glPopMatrix //将一个CCSprite指针以指定的Z顺序并附带一个参数值做为子结点 addChild //有效性判断 CCAssert (child "child should not be null" //将结点转为CCSprite CCSprite *pSprite // check CCSprite is using the same texture id //确保pSprite的纹理与图片集的纹理相同才可以放为子结点 CCAssert (pSprite >getTexture ==m_pobTextureAtlas ),128)">; CCNode (child,zOrder,tag //根据填入的Z顺序值取得pSprite所在的子结点索引放在变量uIndex中 intuIndex =atlasIndexForChild (pSprite,zOrder //将pSprite插入到第uIndex个位置 insertChild //将一个CCNode指针做为子结点 //调用基类的addChild CCNode //将一个CCNode指针以指定的Z顺序做为子结点 //将子结点重新设置Z顺序。 reorderChild //结点参数有效性判断 CCAssert "the child should not be null" //确保此结点是挂在子结点树上。 CCAssert (m_pChildren >containsObject "sprite batch node should contain the child" //如果顺序已经与结点的Z顺序相等则直接返回 (zOrder ==child >getZOrder //子结点引用计数加1 child //将子结点从子结点树上移除 removeChild )child,102)">//按照新的Z顺序插入结点树 addChild //引用计数减1 child >release //将一个CCNode指针从子结点数组中删除,并根所参数决定是否释放元素 removeChild // explicit null handling //确保子结点树中有pSprite CCAssert //移除一个指定的CCSprite指针 removeSpriteFromAtlas //调用基类的移除子结点函数 CCNode //通过索引移除一个子结点,参数doCleanUp决定移除的同时是否对其进行释放。 removeChildAtIndex intuIndex,255)">boolbDoCleanup { removeChild >objectAtIndex (uIndex //将所有的子结点数组元素移除,并根所参数决定是否释放元素 removeAllChildrenWithCleanup boolbCleanup // 如果有子结点 &&m_pChildren >count //遍历子结点调用移除子结点函数 CCObject *pObject ; CCARRAY_FOREACH (m_pChildren,pObject { CCSprite *pChild )pObject ; (pChild ) { removeSpriteFromAtlas } (bCleanup //清空使用此图块集的CCSprite指针数组 m_pobDescendants >removeAllObjects //清空图块集管理器中的图块信息 m_pobTextureAtlas >removeAllQuads //绘制当前CCNode draw //调用基类CCNode的draw函数 CCNode // 如果图块集为空直接返回 >getTotalQuads // 如果图块集不为空 &&m_pobDescendants //遍历所有使用此图块集的CCSprite CCObject (m_pobDescendants,0)">{ // 更新CCSprite的矩阵,注意:此句内部实现将子结点pChild所指的精灵的位置更新到对应的图块集顶点缓冲中。 pChild >updateTransform #if CC_SPRITEBATCHNODE_DEBUG_DRAW // 如果开启调试,则绘制CCSprite的包围矩形 CCRect rect =pChild >boundingBox ; CCPoint vertices { ccp (rect. origin. x,rect. y x +rect. size. width,136)">height ; ccDrawPoly (vertices,0)">#endif // CC_SPRITEBATCHNODE_DEBUG_DRAW // 设置ALPHA混合状态 boolnewBlend =m_blendFunc. ||m_blendFunc. (newBlend { glBlendFunc (m_blendFunc. src,m_blendFunc. //绘制图块集 m_pobTextureAtlas >drawQuads //恢复原ALPHA混合状态 (CC_BLEND_SRC,CC_BLEND_DST //扩容,递增1/3的图块数量 increaseAtlasCapacity // this is likely computationally expensive // 如果当前需要的图块数量比实际图块数量大,则将图块的数量增加1/3。 intquantity >getCapacity / // 打印图块数量的变化信息 CCLOG "cocos2d: CCSpriteBatchNode: resizing TextureAtlas capacity from [%lu] to [%lu].", long )m_pobTextureAtlas )quantity //图块集重新设置数量,resizeCapacity按新的图块集数量重新计算每个图块的纹理UV !m_pobTextureAtlas >resizeCapacity (quantity // 如果失败,返回出错信息。 CCLOG "cocos2d: WARNING: Not enough memory to resize the atlas" ; CCAssert false,0)">"Not enough memory to resize the atla" //重新构建指定的CCSprite指针下的所有子结点的索引 intCCSpriteBatchNode rebuildIndexInOrder *pobParent,102)">//取得参数pobParent的所有子结点数组 CCArray *pChildren =pobParent >getChildren //如果子结点数组不为空 (pChildren &&pChildren //遍历子结点数组并 CCObject (pChildren,64)">&& < { uIndex =rebuildIndexInOrder (pChild,102)">// 如果pobParent !pobParent >isEqual { pobParent >setAtlasIndex ; uIndex } returnuIndex //取得指定CCSprite的所有节点的最大图块索引 highestAtlasIndexInChild //取得指定CCSprite的子结点数组 CCArray =pSprite ; //如果没有子结点,直接返回指定CCSprite的图块索引 !pChildren ||pChildren returnpSprite >getAtlasIndex else returnhighestAtlasIndexInChild >lastObject //取得指定CCSprite的所有节点的最小图块索引 lowestAtlasIndexInChild { CCArray //取得指定CCSprite的子结点数 //取得指定CCSprite的子结点数组 returnlowestAtlasIndexInChild //取得对应的子结点的Z顺序之上或之下的最近图块索引 atlasIndexForChild *pobSprite,255)">intnZ //取得pobSprite的父节点的所有子结点数组。 CCArray *pBrothers =pobSprite >getParent //查询pobSprite在所有子结点数组中的索引 intuChildIndex =pBrothers >indexOfObject (pobSprite ; // 判断当前节点是否是pobSprite的父结点,将结果存入bIgnoreParent。 boolbIgnoreParent (CCSpriteBatchNode // 新建指针变量pPrevIoUs,用于存储pobSprite的前一个结点。 CCSprite *pPrevIoUs (uChildIndex && uChildIndex UINT_MAX //取得pobSprite在所有子结点中的位置前一个节点。 pPrevIoUs (pBrothers // 如果当前节点是pobSprite的父结点。 (bIgnoreParent //如果pobSprite就是第一个子结点。则返回0。 { } //如果pobSprite不是第一个子结点,则返回pobSprite的前一个结点的最大图块索引,加1返回。 (pPrevIoUs // 当前节点不是pobSprite的父结点。 // 如果pobSprite是其父节点的第一子结点 //新建指针变量p,指向pobSprite的父结点。 CCSprite *p ; // less than parent and brothers // 如果nZ小于零,即在其之下的最近索引 (nZ { //返回pobSprite的父结点的图块索引。 returnp { //如果nZ大于零,即在其之上的最近索引 //返回pobSprite的父结点的图块索引值加1。 //如果pobSprite不是其父节点的第一子结点 &&nZ || //返回pobSprite前一个节点的的最大图块索引加1 // 否则返回其父节点的图块索引值加1 // else (prevIoUs < 0 and sprite >= 0 ) CCSprite // 如果进行到这一步,已经出错了。打印出错信息。 CCAssert 0,0)">"should not run here" //将一个CCSprite插入到子节点指针数组的指定位置 insertChild //pobSprite应用此图片集 pobSprite >useBatchNode //设置图块集索引值 pobSprite //设置pobSprite在绘制时需要进行绑定图块的更新 pobSprite >setDirty //如果图块集已经达到最大容量则进行扩容 { increaseAtlasCapacity //在图块集管理器中新增加一个图块,并指定其索引 ccV3F_C4B_T2F_Quad quad >getQuad ; m_pobTextureAtlas >insertQuad &quad,102)">//将pobSprite放入到使用此图集子结点数组的对应位置 m_pobDescendants >insertObject (pobSprite,102)">// 更新索引 //如果使用此图集的子结点数组不为空,遍历并重设一下大于此索引的所有子结点。 { CCObject { >uIndex ) { pChild ; } ++i // 取得pobSprite的子结点数组 CCArray // 如果不为空,遍历并将子结点也按照Z顺序放入到当前CCSpriteBatchNode的子结点数组中。 ; insertChild //移除一个CCSprite removeSpriteFromAtlas *pobSprite // 从图块管理器中移除目标精灵pobSprite所用的图块信息 m_pobTextureAtlas >removeQuadAtIndex //重置目标精灵pobSprite所使用的图块信息 pobSprite >useSelfRender //取得目标精灵pobSprite在CCSpriteBatchNode的子结点中数组中的位置 =m_pobDescendants //如果找到后,从子结点数组中移除它 { m_pobDescendants >removeObjectAtIndex ; // 取得子结点的数组元素数量,遍历大于当前索引的子结点,向前移一个位置。注意:这个for循环从uIndex开始计数。 intcount ;uIndex <count ++uIndex *s ; s (s // 取得目标精灵的子结点数组,遍历并从当前CCSpriteBatchNode的子结点数组中移除。 CCArray //更新Alpha混合状态 updateBlendFunc //如果当前图块集对应的纹理有Alpha通道 >getHasPremultipliedAlpha //设置GL_SRC_ALPHA表示使用源颜色的alpha值来作源混合因子。 m_blendFunc. =GL_SRC_ALPHA // GL_ONE_MINUS_SRC_ALPHA表示用1.0减去源颜色的alpha值来作为目标混合因子。 m_blendFunc. =GL_ONE_MINUS_SRC_ALPHA // 设置Alpha混合状态 setBlendFunc { m_blendFunc =blendFunc // 取得Alpha混合状态 ccBlendFunc CCSpriteBatchNode getBlendFunc { returnm_blendFunc //取得图块集所应用的纹理贴图。 CCTexture2D //设置图块集所应用的纹理贴图 { m_pobTextureAtlas >setTexture //设置完后跟据纹理贴图是否有Alpha通道更新一下混合状态。 updateBlendFunc //从精灵数据中在图块管理器中插入一个新的图块,注意:并不将精灵放入子结点。 addQuadFromSprite { //判断sprite是否有效。 CCAssert (sprite "Argument must be non-nil" //如果指定的索引大于图块集的数量或者图块集的数量已经达到最大值,则需要对图块集进行扩容。 while >=m_pobTextureAtlas ||m_pobTextureAtlas { this >increaseAtlasCapacity //让sprite使用此图集管理器 sprite //设置sprite的图块索引 sprite //新建一个图块顶点信息放入图块信息管理器中。 ccV3F_C4B_T2F_Quad quad =sprite //设置在缓制sprite时更新一下图块信息 sprite //将sprite的顶点位置信息填充入图块顶点缓冲管理器中的顶点数据中。 sprite //在子结点数组指定位置插入一个新的精灵。注意:并不新建图块。 CCSpriteBatchNode addSpriteWithoutQuad //设置sprite的图块索引 child (z //遍历子结点数组查看当前Z值应该排在哪个位置。 >=z //取得位置i,插入child到数组中。 m_pobDescendants //基类同名函数 CCNode } } |
分析这个类的确是费功夫啊,呵呵。继续之前。喝口水先。话说今天听新闻,北京PM2.5浓度又升高了,我可怜的嗓子,担忧中…
走到这里,我们已经了解了CCSpriteBatchNode的作用。其实红孩儿在开发引擎的经历中也有过类似的设计,为了渲染大量相同类型的模型,按照纹理将子模型归类,并将这些纹理进行合并生成大纹理,渲染时设置大纹理就可以渲染出多个不同类型的子模型,如果开启克隆实例,则可以在一个批次内渲出上百个模型。原理相通,目的只有一个,提高渲染效率。
CCLabelBMFont类中关于图字纹理和图块的相关知识我们了解完了,但是我们仍然没有发现Fnt用在哪里,所以我们只理解了一半,现在我们来理解另一半。CCLabelBMFont中使用到一个类CCBMFontConfiguration,它就是用来读取Fnt文件中的文字图片说明信息的。在CCLabelBMFont.h中我们找到它
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 |
classCC_DLL CCBMFontConfiguration
publicCCObject
//通过map容器对字的编码值和对应的信息做映射 std map *m_pBitmapFontArray //FNT文件中的字图块公共项:Height intm_uCommonHeight //FNT文件中的信息:边距,文字与边框的空隙 ccBMFontPadding m_tPadding //FNT文件中的信息:用到的png图 std stringm_sAtlasName //FNT文件中的信息:两个字在先后绘制时的间距调整的信息结构的哈希字典(其实就是个数组,以哈希算法进行存储)。 struct_KerningHashElement *m_pKerningDictionary //构造 CCBMFontConfiguration //析构 virtual~CCBMFontConfiguration //取得描述 //静态函数:将FNT文件加载进来返回一个CCBMFontConfiguration实例对象。 staticCCBMFontConfiguration *configurationWithFNTFile *FNTfile //使用FNT文件初始化 boolinitWithFNTfile //解析FNT文件 voidparseConfigFile *controlFile //从文件中取得字符的编码及UV对应信息 voidparseCharacterDefinition (std stringline,64)">*characterDefinition //从文件取得字体说明 voidparseInfoArguments stringline //从文件取得字符图块公共信息 voidparseCommonArguments //从文件取得图片文件名称 voidparseImageFileName *fntFile //从文件取得要调整间距的字组合信息容量 voidparseKerningCapacity //从文件取得要调整间距的字组合信息 voidparseKerningEntry //从文件取得调整间距的字组合信息字典 voidpurgeKerningDictionary ; |
太棒了,它对Fnt文件做了全面的解析。马上看CPP他是怎么现实的。
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 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
初始化全局容器指针为空
CCMutableDictionary <std string,CCBMFontConfiguration *configurations //全局函数:从Fnt文件中取得一个CCBMFontConfiguration实例对象 CCBMFontConfiguration *FNTConfigLoadFile //创建CCBMFontConfiguration指针变量pRet并置空 CCBMFontConfiguration *pRet //如果容器为空则新建容器 (configurations { configurations newCCMutableDictionary //在容器中取得该文件对应的CCBMFontConfiguration std stringkey (fntFile ; pRet =configurations >objectForKey (key (pRet //如果为空则调用CCBMFontConfiguration静态函数新建一个CCBMFontConfiguration读取文件返回信息结构给pRet pRet =CCBMFontConfiguration configurationWithFNTFile //并将其加入容器中 configurations >setObject (pRet,key returnpRet //释放容器中的数据并释放容器占用内存 voidFNTConfigRemoveCache ; CC_SAFE_RELEASE_NULL //用于进行获取间距调整信息的哈希参数结构 typedef struct_KerningHashElement int key ; // key for the hash. 16-bit for 1st element,16-bit for 2nd element int amount ; UT_hash_handle hh }tKerningHashElement ; //静态函数,从Fnt文件中取得一个CCBMFontConfiguration实例对象 CCBMFontConfiguration *CCBMFontConfiguration //新建一个CCBMFontConfiguration实例对象 CCBMFontConfiguration newCCBMFontConfiguration //使用FNT文件信息初始化 >initWithFNTfile (FNTfile { pRet } CC_SAFE_DELETE //由FNT文件对CCBMFontConfiguration实例对象进行初始化 boolCCBMFontConfiguration initWithFNTfile strlen //解析FNT文件 m_pKerningDictionary ; this >parseConfigFile //构造函数 CCBMFontConfiguration CCBMFontConfiguration :m_pBitmapFontArray newstd { //析构 CCBMFontConfiguration ::~CCBMFontConfiguration //打印日志 CCLOGINFO "cocos2d: deallocing CCBMFontConfiguration" //释放占用内存 CC_SAFE_DELETE (m_pBitmapFontArray >purgeKerningDictionary ; m_sAtlasName. clear //取得描述 "<CCBMFontConfiguration | Kernings:%d | Image = %s>",HASH_COUNT (m_pKerningDictionary c_str //释放间距信息字典 voidCCBMFontConfiguration purgeKerningDictionary { tKerningHashElement *current { current =m_pKerningDictionary ; HASH_DEL (m_pKerningDictionary,current (current } //解析FNT文件 parseConfigFile //通过文件名找出对应的文件路径 std stringfullpath =CCFileUtils fullPathFromRelativePath (controlFile //打开文件进行读操作,执行后会将文件读取到CCFileData创建的内存志中。 CCFileData data (fullpath. "rb" //取得文件大小 longnBufSize =data. getSize //取得CCFileData存储读取信息的内存块。 *pBuffer )data. getBuffer //有效检查 CCAssert (pBuffer,0)">"CCBMFontConfiguration::parseConfigFile | Open file error." !pBuffer } std //将文件信息放入到字符串strLeft中 std stringstrLeft //遍历字符串中每个字符进行解析 (strLeft. length { //根据换行符取出每一行 intpos =strLeft. find '\n' ; //如果不是结尾 (pos )std string npos //取出此行 line substr ; //更新当前字符串为新一行位置后面的字符串 strLeft //取后一行 line =strLeft ; strLeft. erase } //如果是字体介绍信息 (line. "info face" == //解析信息行 this >parseInfoArguments (line //如果是图块公共信息 else "common lineHeight" { //解析图块公共信息 this >parseCommonArguments //如果是指定索引的图片说明信息 "page id" //解析指定索引的图片的说明信息 this >parseImageFileName (line,controlFile //如果是本图片中的字符数量 "chars c" //本句忽略了,无意义,后面读取字符时可以统计 //如果是字符信息 "char" //一个字符的编码对应信息 ccBMFontDef characterDefinition //将本行字符串解析到字符的编码对应信息中 this >parseCharacterDefinition &characterDefinition ; 通过信息索引存入哈希字典 [characterDefinition. charID =characterDefinition //如果有间距调整信息 "kernings count" //那也得解析啊~ this >parseKerningCapacity //解析后面的间距调整 "kerning first" //解析间距调整信息 this >parseKerningEntry //解析指定索引的图片的说明信息 parseImageFileName { //先取得id =line. '=' intindex2 ' ',128)">; std stringvalue (index,index2 //这里只使用了第一张图。所以要求索引为0 CCAssert atoi (value. "LabelBMFont file could not be found" // 取得文件名称 index '"' ; index2 '"',128)">; value //将文件名对应的全路径存入到字符串m_sAtlasName中 m_sAtlasName fullPathFromRelativeFile //解析字体介绍信息 parseInfoArguments { //实际使用中,其实只用到了内边距padding,因为最终显示结果还是需要从图块中获取,既然已经有了图块,那至于字体的字体,大小,是否平滑等信息其实不会影响什么,只是用来做一个说明罢了。 // 内边距padding "padding=" sscanf "padding=%d,%d,%d",64)">&m_tPadding. top,136)">right,136)">bottom,136)">left ; CCLOG "cocos2d: padding: %d,m_tPadding. left,136)">bottom //解析字块公共信息 parseCommonArguments // LineHeight:行高 "lineHeight=" "lineHeight=%u",64)">&m_uCommonHeight // scaleW:图片宽 index "scaleW=" ; CCAssert <=CCConfiguration sharedConfiguration >getMaxTextureSize "CCLabelBMFont: page can't be larger than supported" // scaleH:图片高 index "scaleH=" // pages:共有几张文字图片供使用 index "pages=" "CCBitfontAtlas: only supports 1 page" //packed忽略 //解析字符编码与UV对应信息块 parseCharacterDefinition //读取编码值 "id=" "id=%u",128)">>charID // 在图块中的像素横向位置 index "x=" "x=%f",128)">>rect. // 在图块中的像素纵向位置 index "y=" "y=%f",102)">// 对应图块的宽 index "width=" "width=%f",136)">width // 对应图块的高 index "height=" "height=%f",102)">// 当前字在绘制时的像素偏移横向位置 index "xoffset=" "xoffset=%d",128)">>xOffset // 当前字在绘制时的像素偏移纵向位置 index "yoffset=" "yoffset=%d",128)">>yOffset // 绘制完当前字后,光标向后移多少像素以绘制下一个字 index "xadvance=" "xadvance=%d",128)">>xAdvance //解析某两个字在一起时字距调整信息并存入哈希字典 parseKerningCapacity //同样没有什么意义,字数量可以统过后面的解析统计出来 //解析字距调整信息 parseKerningEntry { // first解析第一个字 intfirst "first=" "first=%d",64)">&first // second:解析第二个字 intsecond ; index "second=" "second=%d",64)">&second // amount:解析要调整的像素个数,负值向左,正值向右 intamount "amount=" "amount=%d",64)">&amount //将对应关系存入哈希字典 tKerningHashElement *element (tKerningHashElement ; element >amount =amount >key (first << 16 | (second & 0xffff ; HASH_ADD_INT } |
CCBMFontConfiguration类分析完了,CCLabelBMFont就很容易理解了。快马加鞭向前冲哟~
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 |
publicCCRGBAProtocol
//容量 CC_PROPERTY (GLubyte,m_cOpacity,Opacity ) //颜色 CC_PROPERTY_PASS_BY_REF (ccColor3B,m_tColor,Color //是否使用透明度来设置RGB值 CC_PROPERTY bool,m_bIsOpacityModifyRGB,IsOpacityModifyRGB // 要渲染的字符串 std stringm_sString //使用的设置 CCBMFontConfiguration *m_pConfiguration //构造函数。 CCLabelBMFont :m_cOpacity ) ,m_bIsOpacityModifyRGB virtual~CCLabelBMFont //释放占用的内存 static voidpurgeCachedData //由一个字符串和字体fnt文件创建图字 boolinitWithString *str,102)">//重点函数:根据字符串和字体信息进行纹理图对应 voidcreateFontChars //设置要渲染的字符串 //取得要渲染的字符串 //设置要渲染的字符串,setString的别名函数 voidsetCString //设置锚点 voidsetAnchorPoint constCCPoint &var //绘制函数 #if CC_LABELBMFONT_DEBUG_DRAW #endif // CC_LABELBMFONT_DEBUG_DRAW : *atlasNameFromFntFile intkerningAmountForFirst shortfirst,255)">shortsecond ; |
CPP文件:
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 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 |
//释放占用的内存
voidCCLabelBMFont purgeCachedData //释放文字FNT信息指针 FNTConfigRemoveCache //静态函数:由一个字符串和字体fnt文件创建图字 CCLabelBMFont *CCLabelBMFont labelWithString //new 出一个新的CCLabelBMFont CCLabelBMFont newCCLabelBMFont //调用其成员函数initWithString创建图字 &&pRet >initWithString (str,102)">//交由内存管理器进行内存管理。 pRet //由一个字符串和字体fnt文件创建图字 boolCCLabelBMFont initWithString *theString,0)">(theString (m_pConfiguration ; // allow re-init //调用FNTConfigLoadFile读取Fnt文件并返回出信息的内存地址给指针变量m_pConfiguration m_pConfiguration =FNTConfigLoadFile //用到它就给它的引用计数器加1 m_pConfiguration (m_pConfiguration,0)">"Error creating config for LabelBMFont" //由信息指针取得字体图和字符串长度来初始化图块集管理器。 >m_sAtlasName. //如果成功,容量设为255 m_cOpacity 255 //使用白色 m_tColor =ccWHITE //m_tContentSize是CCNode中变量,为结点原始大小,不受矩阵变换影响,这里初始化为零大小 m_tContentSize =CCSizeZero //如果纹理有Alpha通道,则使用透明度设置RGB值。 m_bIsOpacityModifyRGB //设置锚点在正中心 setAnchorPoint (ccp ( 0.5f,0.5f //设置字符串 this >setString //析构函数 CCLabelBMFont ::~CCLabelBMFont //释放字符串容器,释放 m_sString. // 由参1和参2组成key从哈希表中找到元素的数量。 intCCLabelBMFont kerningAmountForFirst intret //将两个字合并为双字做为key来进行哈希表查找 intkey //如果Fnt信息中有字距调整信息 >m_pKerningDictionary //使用哈希算法找到对应的字距信息值 tKerningHashElement ; HASH_FIND_INT >m_pKerningDictionary,64)">&key,128)">; //如果找到返回 (element ) ret =element //计算Char对应的UTF8码的掩码和长度 #define UTF8_COMPUTE(Char,Mask,Len) \ if (Char < 128) \ { \ Len = 1; \ Mask = 0x7f; \ } \ else if ((Char & 0xe0) == 0xc0) \ { \ Len = 2; \ Mask = 0x1f; \ } \ else if ((Char & 0xf0) == 0xe0) \ { \ Len = 3; \ Mask = 0x0f; \ } \ else if ((Char & 0xf8) == 0xf0) \ { \ Len = 4; \ Mask = 0x07; \ } \ else if ((Char & 0xfc) == 0xf8) \ { \ Len = 5; \ Mask = 0x03; \ } \ else if ((Char & 0xfe) == 0xfc) \ { \ Len = 6; \ Mask = 0x01; \ } \ else \ Len = -1; //计算Char对应的UTF8码的长度 #define UTF8_LENGTH(Char) \ ((Char) < 0x80 ? 1 : \ ((Char) < 0x800 ? 2 : \ ((Char) < 0x10000 ? 3 : \ ((Char) < 0x200000 ? 4 : \ ((Char) < 0x4000000 ? 5 : 6))))) //取得Char对应的UTF8码 #define UTF8_GET(Result,Chars,Count,Len) \ (Result) = (Chars)[0] & (Mask); \ for ((Count) = 1; (Count) < (Len); ++(Count)) \ { \ if (((Chars)[(Count)] & 0xc0) != 0x80) \ { \ (Result) = -1; \ break; \ } \ (Result) <<= 6; \ (Result) |= ((Chars)[(Count)] & 0x3f); \ } //判断Char是否是有效的Unicode码 #define UNICODE_VALID(Char) \ ((Char) < 0x110000 && \ (((Char) & 0xFFFFF800) != 0xD800) && \ ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \ ((Char) & 0xFFFE) != 0xFFFE) //用于获取UTF8下个字符的编码偏移。 charutf8_skip_data 256 { 5,221)">1 constg_utf8_skip =utf8_skip_data //取得UTP8编码字符的下一个字符。 #define cc_utf8_next_char(p) (char *)((p) + g_utf8_skip[*(unsigned char *)(p)]) //返回取得字符串转换为UTF8后的字符长度 long cc_utf8_strlen *p,255)">intmax longlen ; *start =p ; (p ||max ) { } (max { p =cc_utf8_next_char ; ++len } ; p ; -start <max ; p } /* only do the last len increment if we got a complete * char (don't count partial chars) */ ==max returnlen //将Unicode编码字符串p转换为UTF8编码 int cc_utf8_get_char inti,mask intresult charc ; UTF8_COMPUTE (c,mask,0)">(len ; UTF8_GET (result,p,i,255)">returnresult //重点函数:由字符串和字编码纹理块对应信息设置到 createFontChars intnextFontPositionX //下一个字的横向绘制位置 intnextFontPositionY //下一个字的纵向绘制位置 shortprev //上一个字编码 intkerningAmount ; //字间距调整的像素数量 CCSize tmpSize // intlongestLine // 最长的一行的宽度 inttotalHeight //字符串的总高度 intquantityOfLines //如果字符串长度为零直接返回 ==m_sString. } //取得字符串转换为UTF8后的字符长度 intutf8len =cc_utf8_strlen (m_sString. (utf8len //将字符串转换为UTF8的字符串 short *pUniStr [utf8len ; pUniStr =m_sString. <utf8len { pUniStr =cc_utf8_get_char ; p intstringLen =cc_wcslen (pUniStr //统计行数 <stringLen shortc =pUniStr (c { quantityOfLines //由行高乘行数最得要显示的字符串占用的总高度 totalHeight =m_pConfiguration >m_uCommonHeight *quantityOfLines //统计字符串的起始位置高度 nextFontPositionY -m_pConfiguration //遍历所有的字 ; //如果遇到换行符则进行换行处理 nextFontPositionX ; nextFontPositionY continue } //查找是当前字的纹理映射信息结点 std iteratorit >m_pBitmapFontArray >find (it >end "LabelBMFont: character is not supported" //根据上一个字与当前字进行间距调整信息哈希表的查找,返回调整的像素偏移量。 kerningAmount =this >kerningAmountForFirst (prev,c //取得当前字的纹理映射信息结点 constccBMFontDef &fontDef [c //取得当前字在贴图上的像素矩形 CCRect rect =fontDef. rect //取得对应当前字的精灵 CCSprite *fontChar ; fontChar (this >getChildByTag ; !fontChar //如果找不到,则新建精灵,并将纹理上对应像素块信息传给精灵进行初始化。 fontChar newCCSprite ; fontChar >initWithBatchNodeRectInPixels this,rect ; //将精灵加入到子结点,设置i为附带查找唯一ID this >addChild (fontChar,102)">// 将纹理上对应像素块信息传给精灵。 fontChar->setTextureRectInPixels(rect,false,rect.size); //设置其显示,完全不透明。 fontChar >setIsVisible >setOpacity //设置字的纵向偏移 floatyOffset float -fontDef. yOffset //计算字的位置,注意:因为锚点设的精灵正中心,所以位置应该是左下角位置加上大小的一半再进行相关偏移和间距调整计算。 fontChar >setPositionInPixels (nextFontPositionX +fontDef. xOffset rect. / 2.0f +kerningAmount, )nextFontPositionY +yOffset -rect. ; // NSLog(@"position.y: %f",fontChar.position.y); // 更新绘制下一个字的横向位置 nextFontPositionX ]. xAdvance +kerningAmount //更新上一个字符供循环再次使用 prev =c // 设置是否用透明度设置色彩 fontChar->setIsOpacityModifyRGB(m_bIsOpacityModifyRGB); //设置色彩, fontChar >setColor (m_tColor //如果透明度小于255,设置透明度 (m_cOpacity { fontChar //取得最长的一行的宽度 (longestLine <nextFontPositionX { longestLine =nextFontPositionX //设置当前字符串在屏幕上占用的矩形位置 tmpSize. )longestLine ; tmpSize. )totalHeight //调用基类CCNode的函数设置为原始大小 this >setContentSizeInPixels (tmpSize //释放字符串 CC_SAFE_DELETE_ARRAY //LabelBMFont重载基类 CCLabelProtocol的接口函数 //设置字符串 setString *newString //将newString保存入字符串成员变量m_sString m_sString. ; m_sString =newString //因CCLabelBMFont派生于CCSpriteBatchNode,m_pChildren为其子节点数组,这里进行遍历将其所有显示中的字精灵都设为不显示 { CCNode *pNode )child (pNode { pNode //重新由字符串和字体信息创建要显示的字精灵 this >createFontChars //取得字符串 getString returnm_sString. // setString别名函数 setCString { setString (label //LabelBMFont 重载基类 CCRGBAProtocol 的接口函数 setColor { m_tColor //因CCLabelBMFont派生于CCSpriteBatchNode,m_pChildren为其子节点数组,这里进行遍历设置 &CCLabelBMFont getColor returnm_tColor setOpacity (GLubyte var { m_cOpacity { CCRGBAProtocol *pRGBAProtocol dynamic_cast <CCRGBAProtocol (pRGBAProtocol { pRGBAProtocol } //取得透明度 GLubyte CCLabelBMFont getOpacity returnm_cOpacity //设置是否使用透明度设置RGB值 setIsOpacityModifyRGB boolvar { m_bIsOpacityModifyRGB { //因子结点即是精灵CCSprite,CCSprite又派生于CCRGBAProtocol,故进行转换 CCRGBAProtocol //调用setIsOpacityModifyRGB进行设置 pRGBAProtocol >setIsOpacityModifyRGB (m_bIsOpacityModifyRGB //取得是否使用透明度设置RGB值 getIsOpacityModifyRGB returnm_bIsOpacityModifyRGB // 设置锚点 setAnchorPoint &point !CCPoint CCPointEqualToPoint (point,m_tAnchorPoint { CCSpriteBatchNode (point ; this //绘制图字标签,Debug模式下手动调用绘制 #if CC_LABELBMFONT_DEBUG_DRAW //绘制图块集 CCSpriteBatchNode //绘制边框 constCCSize &s >getContentSize ; CCPoint vertices { ccp (s. ; ccDrawPoly #endif // CC_LABELBMFONT_DEBUG_DRAW } |
照例做个总结:
1. 图字的原理:将所要绘制的字绘制到图片上,通过编码取得对应的矩形块UV进行顶点缓冲的设置之后进行绘制。Cocos2d-x提供的两个类非常重要:(1) CCTextureAtlas(2) CCSpriteBatchNode。
2. 图字的组成:一张纹理,一个纹理描述信息文件。缺一不可。要做好图字,必须深入理解图字纹理描述信息文件的格式,可能看Cocos2d-x提供的类: CCBMFontConfiguration,并掌握图字工具的使用。
呃,网上提供了一些图字工具,比较常用的有
Hiero: