资源预览内容
第1页 / 共29页
第2页 / 共29页
第3页 / 共29页
第4页 / 共29页
第5页 / 共29页
第6页 / 共29页
第7页 / 共29页
第8页 / 共29页
第9页 / 共29页
第10页 / 共29页
亲,该文档总共29页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
游戏中汉字显示实现及技巧作者:炎龙工作室 千里马肝版本:v1.0最后更新日期:2002-3-30绪言在游戏中,因为我们是中国人麻,通常都需要显示汉字,比方说交待剧情。而对于文字显示,英文显示要较其简单得多,因为只有26个字母,就算再加一些标点、符号什么,用一张位图,就可以足以显示所有单词了,而相关实现技巧,也比较轻松。而中文显示方法,要复杂得许多。记得原来在DOS下,汉字显示都是读UCDOS点阵字库,而点阵字库读取方法,在UCDOS SDK中都有源代码可以参考。但是自从Windows操作系统开始,我们开始了解到一种更好字库,它就是TTF。注:以下我所指开发环境,除非明确说明,默认平台是VC6.0+DirectX8.1,使用D3D来加速2D。然后使用STL是用SGI实现那一套STL。点阵字库包括现在,有很多游戏都还是使用点阵字库。因为操作起来比较方便,加上这方面经验已经积累了好几年了。通常如果只是一种字体就可以满足需要话,它会是一个比较好、快解决办法。但是它有3个缺点:1. 如果放大显示,不做处理话,显示出来汉字,是很难看。2. 像是UCDOS所提供点阵字库,只有24点阵有几种字体,如:宋体、黑体、揩体,而16点阵好象就只有宋体一种。3. 点阵字库,通常是有版权,尤其是第三方制作汉字库(如:方正)。在这样情况下,当我们写好这样一个显示函数,就算是解决了如:放大、快速显示等问题话,可供选择字体还是太过于局限了。所以,在字体要求比较强情况下,点阵字库并不是一个好解决方法,他不够灵活。尽管我们对于它操作是如此得熟练,可以写出优美代码来展示我们编程技巧。TTFTTF是True Type Font简称。在WindowsFonts目录下面,我们可以看到许多后缀为ttf文件,它就是接下来我们接下来所要谈到。TTF是一种矢量字库。我们经常可以听到矢量这个词,像是FLASH中矢量图形,在100*100分辨率下制作flash,就算它放大为全屏,显示出画面也不会出现马赛克。所谓矢量,其实说白了就是用点和线来描述图形,这样,在图形需要放大时候,只要把所有这个图形点和线放大相应倍数就可以了。而且,在网站上有很多TTF字库可以下载,或者你可以去买一些专门字库光盘。然后在你发行你精心制作游戏时,可以顺便捎上这些后缀为.ttf文件就行了。包括Quake这样惊世之作,也都是用TTF字库。这样,我们就可以解决点阵汉字一些问题。通过TTF,我们在字体质量和字库数量上获得了暂时性胜利。字库读取和显示先前谈到点阵字库,只需要很简单一些操作,就可以显示出想要汉字。下面我给出一个读取hzk16函数,它需要一个Surface以供显示用:#include #include #include / 读取16x16void DispHZ16(int x, int y, BYTE *Str, LPDIRECTDRAWSURFACE surf)const int Mask = 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 ;FILE *HzkFp;WORD i, j, k=0, m;WORD HzNum;WORD QuHao;WORD WeiHao;long offset;BYTE dotBuffer32;HzkFp = fopen(HZK16, rb);HzNum = strlen(const char *)Str)/2;DDSURFACEDESC ddsd;LPWORD lpSurface;HRESULT ddrval; ddsd.dwSize = sizeof(ddsd);while(ddrval=surf-Lock(NULL, &ddsd, 0, NULL)=DDERR_WASSTILLDRAWING);if(ddrval = DD_OK)lpSurface = (LPWORD)ddsd.lpSurface;for(i = 0; iHzNum; i+)QuHao = Stri*2-160;WeiHao = Stri*2+1-160;offset = (QuHao - 1) * 94 + (WeiHao-1)*32;fseek(HzkFp, offset, SEEK_SET);fread(dotBuffer, 32, 1, HzkFp);for(j=0;j16;j+) for(k=0;k2;k+) for(m=0;mUnlock(NULL);fclose(HzkFp);其实原理很简单:1. 打开字库2. 计算字符串长度(这个函数只支持中文),并且Lock Surface3. 依次计算出每个汉字所对应区码和位码(汉字第1个字节是区码,第2个字节就是位码),然后通过公式计算出这个汉字在字库中偏移量:offset = (QuHao - 1) * 94 + (WeiHao-1)*32;4. 读出一个32个字节点阵5. 绘制到Surface上以上只是1616点阵字库显示方法,2424读取方法及之类似,大家可以参照相关资料来书写出自己代码。如何显示TTF字库呢,有很多种手段,下面我按从简单到复杂顺序依次介绍:1. 使用Windows API,也就是大家所熟悉TextOut。通过它,还需要一个HDC(设备句柄),我们就可以随意地在屏幕任何地方显示出文字了。2. 在,有一个FreeType免费库,而且是OpenSource。它目前有2个版本:1.0和2.0。其区别在于,1.0只能读取TTF格式,而2.0支持更多文件格式,在使用它之前请详细阅读所要遵循Licence,以下是摘自FreeType2.0对字库支持列表:o TrueType fonts (and collections) o Type 1 fonts o CID-keyed Type 1 fonts o CFF fonts o OpenType fonts (both TrueType and CFF variants) o SFNT-based bitmap fonts o X11 PCF fonts o Windows FNT fonts 3. 自己研究TTF格式,然后自己来操作。晕. /倒! 虽然我们想要把每一件事情都做好,但是也不是每一件事情都要亲历亲为。如果你非要这样,也行_,但是过不了多久,你就会陷入泥沼,到时候你会发现自己热情正在慢慢被磨灭,什么叫做抓狂,相信你很快就会知道_。在有多种选择可以取舍情况下,我们需要考虑一下,对比一下各种解决方法优劣。在DirectDraw时代,我们都不自觉地喜欢上了GetDC,因为多方便啊。可是现在已经到了DirectX8.1时代了(我要使劲地摇那些还沉醉于DirectX7中,为如何在使用alpha时提升那可怜1、2个fps朋友们:醒醒,该起床了!),HDC已经被M$列为禁用品。怎么办呢?是,你可能已经想到了,我们还一直保存着窗口hWnd呢,可以通过它来得到hdc,从而调用那些需要hdcAPI,可是,这样做是更为愚蠢,这样对你是没有一点好处,不信,你就试试吧。有一句话,请牢记:要想你游戏有更快速度话,请不要再去碰HDC了。我们非常清楚hdc是一个超慢解决办法,它无法在我们高速游戏中满60分及格。下面来看看FreeType,它更像是一个Service。它解决方法是,先通过一系列初始化和设置,告诉FreeType字体名字和大小等,然后它会动态地申请一个Graphic,再把我们要显示字画到这个Graphic上,你还可以把它保存为tga格式。不过我们最终所想要不是这个,所以可能我们还需要从这个Graphic上逐点读取或者用CopyRect,然后再画到我们画面上。其实它已经是很方便了,可是需要你去学习如何配置和使用它,这是很花时间一件事情,而且它最大优点是可以跨平台,我们需要它吗?如果有一个更为简单办法,像是如果Textout不是那么慢话,就好了在这里,顺便谈一下另2个字体显示类:ID3DXFont和CD3DFONT。可能早就有人会说怎么在上面列表中没有它们?原因我会在下面慢慢地说明:ID3DXFont,它存在于D3DX库中,一个现成字体类,不过对于它处理方法我实在不敢恭维,就引用一位大师所说话来表达我看法吧: 在内部实现中, ID3DXFont:DrawText()函数确实做了我上面讨论工作,先建立一张GDI兼容位图,把文本绘制到位图上,而后把位图拷贝到纹理贴图上去,最后把纹理渲染到屏幕上。这样你就聚齐了所有龟速原始GDI函数,还包括了一大堆额外开销 最终,这个函数比原来GDIDrawTextEx()函数要慢上超过六倍CD3DFONT,是由M$在D3D框架代码中提供。不过它只能显示英文,有很多朋友通过自己定制和修改这个类,来实现自己中文显示。不过效果都不是很好。其实原理,跟ID3DXFont方法差不多,不过处理方法要聪明了一点。分析及思考那么我们应该怎么办呢?通常我们会幻想,如果可以像处理英文那样,把所有汉字都保存在一张位图里,该有多好。这样,显示速度就不是问题了,直接可以CopyRect上去。可是,这样可能吗?首先,必须每一种字体都要生成这样一个巨型位图。而且据说在GB2312中,一共有6000多个汉字,就算是用16*16,oh my god,这个位图该有多大啊(据说会有2.5M_)!而且在DirectX8.1中,对于Texture(显示最小单位,就好象是原来DirectSurface概念一样。说过多少遍了,不要再用DirectX8以前东西了。不要试着去回忆那些美好过去,我很明白,要你一下子放弃原来多年所获得成就,是一件很痛苦事情,但是包袱太重,是会影响进步。就像是我们国家扯远了),不同显卡,支持最大容量也是不同。比方说早期Voodoo,只支持256*256大小Texture。而在我显卡(Geforce2 MX 200)上测试,支持最大2048*2048大小Texture。对于这样硬件不确定性,我们只能取其最小值,也就是256*256。汉字虽然很多,但是常用汉字,其实也就只有那么几百个。像这样字:鬯、鞴,你一辈子会看到多少次呢?如果可以做一个类似于Cache东西,保存着常用那些个汉字,在需要显示时候,先在Cache中查找,如果有话,就马上画上去;如果没有,就从字库中提取到Cache中。这样话,在使用Texture来保存汉字位图信息同时,对于每个汉字,我们还要定义一个结构,然后用一个东西把它串起来,综合它们2个,也就实现了我们所要Cache了。刚开始,我所定义结构是这样:struct Char char hz3; / 保存汉字 int frequency;/ 使用频率 RECT rect; / 这个字对应位图区域 Bool is
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号