游戏里到底有多少真的汉子游戏功略

游戏中打字怎么样拼音变汉子_百度知道
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。
游戏中打字怎么样拼音变汉子
我有更好的答案
按键盘上的 shift和ctrl 补充:一起按
采纳率:96%
为您推荐:
其他类似问题
您可能关注的内容
拼音的相关知识
换一换
回答问题,赢新手礼包后使用快捷导航没有帐号?
查看: 23966|回复: 85
菊花残 满地红
新人欢迎积分1 阅读权限99积分35951精华1UID6429238帖子金钱98856 威望33
一入菊门深似海,无人知是黄瓜来 . ...
Lv.10, 积分 35951, 距离下一级还需 19049 积分
UID6429238帖子威望33 多玩草488 草
这两天看见某个女汉子教大家怎么辨别游戏里面的人妖绿茶和妹子
把妹子说的那个娇羞哦
其实我就挺想说,玩游戏的妹子,有几个是娇羞的?真是容易害羞的那还玩个屁的游戏
在游戏这个大染缸里面混久了,多娇羞的人都会变的不娇羞,多让人怜惜的林黛玉都可以变成抠脚大妹子,就算你外表再怎么白富美
我表姐被我带来玩游戏,从一个从不爆粗口的人变成偶尔爆粗口了
其实挺不喜欢女汉子自称的(有段时间自己也自称过女汉子,那时候纯粹是被周围朋友叫我纯爷们叫疯了才这么说,要说我这个ID,很多人到现在还会以为我是汉子吧),虽然不敢说是绿茶婊什么装的啊,其实觉得蛮矫情的
以前觉得女汉子还没什么,现在越来越多的自称女汉子的让我觉得女汉子也挺恐怖的
为什么呢?因为太多证明女汉子集合了男人的粗暴和女人的小心眼,别说我这句话说的对不对
根据我混论坛这么多年玩游戏这么多年,那些所谓的真·女汉子有几个是能达到的?能做到不矫情吗?这是基础(如果你要说男人还有娘C的,那我也就没办法了,娘C这个词好好想想吧)
玩游戏怎么分辨真·妹子?这个游戏其实也挺好认的,但是不乏有真·汉子装作假·妹子呢?(这点就不说了,毕竟装到真是,人家视频过了什么都弄了根本没办法去辨别了)
一般妹子玩游戏分几种性格
天真可爱型(俗称脑残性):这种妹子大多年纪不大,可能高中生,也有可能大学生,性格都是唯我独尊喜欢出风头的,喜欢刷喇叭,遇见一点不顺心的或者是做任务途中被人抢怪啊杀了啊什么的就喜欢骂人,而且骂得很难听,还喜欢到处找老公,或者打着给朋友找老公的名义顺便给自己也找个老公。当然游戏里面肯定也有真·天真可爱的,但是这种,呵呵,凤毛麟角,至少我这几年就只遇见一个妹子是这种。
话少冷静型(表示这只是表象,你只是和她不熟):这种妹子一般遇见不认识的人可能不会主动搭话,除非遇见不懂的才会询问一下,平时你不说话她肯定是不会主动说话的,但是一熟悉起来,就不会觉得她是话少。PS:有几个妹子话少啊?话少的妹子会来玩游戏?你现实中认识的熟悉的妹子有几个话少看看就知道了。不然怎么说三个女人一台戏。
御姐型:这类妹子天生性格比较泼辣豪迈,可以是无忌惮的调戏任何妹子包括汉子,什么话都说得出口,但是不代表就是脏话。天生能活跃气氛,哪怕是一个陌生的团体都可以和不认识的人聊的很嗨
技术型:这类妹子很霸气啊,各种性格的都有各种性格的都乱入啊,但是技术那是杠杠的啊,可能比很多汉子技术还好,一般遇见这种妹子很多人会认为是个汉子还会为他默默点赞吧
卖萌型:这种妹子不用说了,很多汉子很受用,大家都懂的
真·妹子假·汉子型:这类型妹子应该就是深受腐文化的侵入,脑子里面除了腐剩下的百分之一就只有未知生物了。而且这类型妹子玩的号可能是男号也可能是女号,最好辨别的方式就是看名字ID,很明显就可以认出来,如果她隐藏的很深不说自己是妹子的时候,你会一直以为他是个抠脚大汉。
二缺型:没错,真有这种妹子,经常做一些傻事让整个队伍刷BOSS的时候团灭,当然,这个不是她愿意的,相信吧,她只是二缺,天生少根筋不说还她喵手残
自强型:从不以妹子身份自居也不会因为自己的妹子身份就认为男人就该让着你,自己赚钱自己和人组队刷本,不酱油不划水,欠了的人情也会及时还清,其他,就是字面意思了(在这个社会,哪怕是游戏,别人不会因为你是妹子在做势力任务的时候别人就不杀你,你看见谁杀人的时候会问你是不是真妹子的?)
还有一种就是各种乱入型(俗称精分抽风型,以上啥都可能占全了)
绿茶婊什么的,还真不太好分辨了,因为人家会隐藏,以上各种类型里面都随机粗线绿茶婊
其实还有很多细分不出来,毕竟每个妹子的性格都有所不同,只要你会伪装,妹子也可以变汉子,汉子也可以变妹子
其实分辨妹子汉子什么的都无所谓,反正都是玩游戏,你又不去找老公把妹的话,什么性别的都无所谓,只要玩的开心,那就是HAPPYEND!
发这个帖子也没别的意思,就是想说,别把游戏里面的妹子想的那么娇羞,如果一个妹子真的娇羞,会随便和陌生人QT或者YY?
此贴也没其他意思,毕竟玩游戏对方是不是女的也无所谓,就像我上面说的,又不找老公老婆,但是那些所谓的道德家,你觉得这个话题无聊你可以不用进来看啊?我求你进来的啊?标题都写了是什么,如果是你雷点你可以滚粗,别又要点进来又要装作自己站在最高点上说话好不?我就一普通玩家,没有你觉悟高你何必和我一矫情加小心眼的人一般见识是不?
忘记还有一类人了,就是用圣人的标准要求别人,贱人的标准衡量自己了
本帖最后由 纯良滴人 于
16:59 编辑
&你以为你换个马甲我就不认识你了&
&就一句话,游戏宠出来的女子,就算你自认为踩狗屎娶进家门以后也有你受的...&
&我玩游戏从来就没人知道我是女的。。&
&PS 我游戏从来不骂脏话,不过咱骂人不需要脏字&
&表示我玩游戏基本是男号,偶尔玩女号还被当做人妖,楼主请问这类是那款啊=。=&
:还不是一样,就我说的这几种,你注意下,就能分辨出是男是女,就算她玩的是男号除非她不怎么和游戏里面的人怎么接触,一般从说话什么的还是能分辨出的 &
&楼主!你跑题了!说是分辨妹纸,你这是分辨么?你这是在分类~~不是分辨!&
&楼主!你跑题了!说是分辨妹纸,你这是分辨么?你这是在分类~~不是分辨!&
俄是各种乱入型
快成浑天所有工会黑名单上的人了 不过从不打妹子旗号出门
能打就打 打不过就跑&
&总是有那么些自己想的阴暗说别人想的阴暗的人,哎~&
青山绿水最蓝天
新人欢迎积分1 阅读权限70积分5104精华0UID帖子金钱18713 威望3
Lv.7, 积分 5104, 距离下一级还需 4896 积分
UID帖子威望3 多玩草570 草
我都屏蔽F2 语音了,至于对方是男是女 对我来说 无所谓 ~ 我只在乎档我在 白雾森林做任务,会不会锁定我
打酱油滴..
新人欢迎积分1 阅读权限80积分16215精华1UID2943986帖子金钱6812 威望9
丶电二大漠流沙小气功
Lv.8, 积分 16215, 距离下一级还需 3785 积分
UID2943986帖子威望9 多玩草311 草
娇羞的还是有的。。。只是我碰上后都觉得好别扭。。QT里面也直接无视。
新人欢迎积分1 阅读权限90积分20989精华0UID4086744帖子金钱11205 威望-8
飞天小男警
Lv.9, 积分 20989, 距离下一级还需 14011 积分
UID4086744帖子威望-8 多玩草71 草
QT一开不就清楚了,再说,辨别这么有什么用,你能上人家还是怎么的?
菊花残 满地红
新人欢迎积分1 阅读权限99积分35951精华1UID6429238帖子金钱98856 威望33
一入菊门深似海,无人知是黄瓜来 . ...
Lv.10, 积分 35951, 距离下一级还需 19049 积分
UID6429238帖子威望33 多玩草488 草
木偶丶tokio 发表于
娇羞的还是有的。。。只是我碰上后都觉得好别扭。。QT里面也直接无视。
真娇羞假娇羞分不出?有几个是真娇羞的?玩游戏来娇羞?可以滚粗负分了,娇羞的人还会QT还会和人YY?
菊花残 满地红
新人欢迎积分1 阅读权限99积分35951精华1UID6429238帖子金钱98856 威望33
一入菊门深似海,无人知是黄瓜来 . ...
Lv.10, 积分 35951, 距离下一级还需 19049 积分
UID6429238帖子威望33 多玩草488 草
世界少女的梦想 发表于
QT一开不就清楚了,再说,辨别这么有什么用,你能上人家还是怎么的?
有个词语叫家里有个姐姐或者家里有个妹妹,我会说我有个现实中的男性朋友,玩了几年游戏到现在一直没人看穿他是男的吗?他还混LOL论坛,经常爆照,照片上过推荐,具体是谁,呵呵呵呵
新人欢迎积分0 阅读权限70积分9960精华0UID帖子金钱15705 威望6
心若沉浮 浅笑安然
Lv.7, 积分 9960, 距离下一级还需 40 积分
UID帖子威望6 多玩草280 草
纯良滴人 发表于
这两天看见某个女汉子教大家怎么辨别游戏里面的人妖绿茶和妹子
把妹子说的那个娇羞哦
打酱油滴..
新人欢迎积分1 阅读权限80积分16215精华1UID2943986帖子金钱6812 威望9
丶电二大漠流沙小气功
Lv.8, 积分 16215, 距离下一级还需 3785 积分
UID2943986帖子威望9 多玩草311 草
其实还是一句,玩游戏只图自己开心。
我见不得那些围着妹子转的男人。。唉。。感觉很丢男人的脸哎
菊花残 满地红
新人欢迎积分1 阅读权限99积分35951精华1UID6429238帖子金钱98856 威望33
一入菊门深似海,无人知是黄瓜来 . ...
Lv.10, 积分 35951, 距离下一级还需 19049 积分
UID6429238帖子威望33 多玩草488 草
木偶丶tokio 发表于
其实还是一句,玩游戏只图自己开心。
我见不得那些围着妹子转的男人。。唉。。感觉很丢男人的脸哎 ...
给你点32个赞再给个好评
新人欢迎积分1 阅读权限40积分352精华0UID帖子金钱3097 威望0
Lv.4, 积分 352, 距离下一级还需 648 积分
UID帖子威望0 多玩草0 草
我是来的经验的
[img][/img]
新人欢迎积分1 阅读权限40积分513精华0UID9752963帖子金钱2136 威望0
Lv.4, 积分 513, 距离下一级还需 487 积分
UID9752963帖子威望0 多玩草10 草
木偶丶tokio 发表于
其实还是一句,玩游戏只图自己开心。
我见不得那些围着妹子转的男人。。唉。。感觉很丢男人的脸哎 ...
一听是个妹子就开始跪舔 游戏里这种饥渴的精虫上脑男见过不少 恶心死了简直
单纯的玩游戏不好么
新人欢迎积分1 阅读权限100积分60320精华0UID帖子金钱9005 威望1
Lv.11, 积分 60320, 距离下一级还需 29680 积分
UID帖子威望1 多玩草20 草
这些我都知道呢& & 。。。。。。。。。。
我是制服控
新人欢迎积分1 阅读权限50积分1286精华0UID帖子金钱40903 威望0
Lv.5, 积分 1286, 距离下一级还需 1214 积分
UID帖子威望0 多玩草320 草
女汉飘过。。。
花花世界,爱的不够才会诸多借口~&&平价定制各类模型,有意者站短。。
窗台上有只鸟
新人欢迎积分1 阅读权限90积分21407精华0UID帖子金钱34751 威望10
爱上一个学姐可我的校长是她干爹
Lv.9, 积分 21407, 距离下一级还需 13593 积分
UID帖子威望10 多玩草185 草
是不是妹子该我啥事 我又不能上了她&&
新人欢迎积分0 阅读权限60积分3068精华0UID帖子金钱889 威望2
?沉下手中恩怨剑?  ?从此不问江湖事?
Lv.6, 积分 3068, 距离下一级还需 1932 积分
UID帖子威望2 多玩草6 草
这个好像是在没发现有F2的情况下吧?
元宝专属一阶勋章。已绝版
终极人缘勋章
终极人缘勋章
多玩写手勋章
多玩写手勋章
甜蜜情侣勋章
甜蜜情侣勋章
贴图新苗勋章
贴图新苗勋章
九阴功勋勋章
九阴功勋勋章
初级灌水标兵
初级灌水标兵
LOL战斗力9000以上
马年新春勋章
手机APP马年迎春,马上有钱!
爱情守望者
爱情守望者
节日守望者
节日守望者
初级在线标兵
论坛在线时间达1000小时即可申请
使命召唤OL功勋勋章
战争来了又走,而战士永远忠诚
需要金钱:1100
手机盒子客户端点击或扫描下载
Powered by游戏中汉字显示的实现与技巧[ZZ]
我的图书馆
游戏中汉字显示的实现与技巧[ZZ]
绪言 在游戏中,因为我们是中国人麻,通常都需要显示汉字,比方说交待剧情。而对于文字的显示,英文的显示要较其简单得多,因为只有26个字母,就算再加一些标点、符号什么的,用一张位图,就可以足以显示所有的单词了,而相关实现技巧,也比较轻松。 而中文的显示方法,要复杂得许多。记得原来在DOS下,汉字的显示都是读的UCDOS的点阵字库,而点阵字库的读取方法,在UCDOS SDK中都有源代码可以参考。但是自从Windows操作系统开始,我们开始了解到一种更好的字库,它就是TTF。 注:以下我所指的开发环境,除非明确说明,默认的平台是VC6.0+DirectX8.1,使用D3D来加速2D。然后使用的STL是用的SGI实现的那一套STL。 点阵字库 包括现在,有很多游戏都还是使用的点阵字库。因为操作起来比较方便,加上这方面的经验已经积累了好几年了。通常如果只是一种字体就可以满足需要的话,它会是一个比较好、快的解决办法。但是它有3个缺点: 1.如果放大显示,不做处理的话,显示出来的汉字,是很难看的。 2.像是UCDOS所提供的点阵字库,只有24点阵的有几种字体,如:宋体、黑体、揩体…,而16点阵的好象就只有宋体一种。 3.点阵字库,通常是有版权的,尤其是第三方制作的汉字库(如:方正)。 在这样的情况下,当我们写好这样的一个显示函数,就算是解决了如:放大、快速显示等问题的话,可供选择的字体还是太过于局限了。所以,在字体的要求比较强的情况下,点阵字库并不是一个好的解决方法,他不够灵活。尽管我们对于它的操作是如此得熟练,可以写出优美的代码来展示我们的编程技巧。 TTF TTF是True Type Font的简称。在Windows\Fonts目录下面,我们可以看到许多后缀为ttf的文件,它就是接下来我们接下来所要谈到的。 TTF是一种矢量字库。我们经常可以听到矢量这个词,像是FLASH中的矢量图形,在100*100分辨率下制作的flash,就算它放大为全屏,显示出的画面也不会出现马赛克。所谓矢量,其实说白了就是用点和线来描述图形,这样,在图形需要放大的时候,只要把所有这个图形的点和线放大相应的倍数就可以了。而且,在网站上有很多的TTF字库可以下载,或者你可以去买一些专门的字库光盘。然后在你发行你精心制作的游戏时,可以顺便捎上这些后缀为.ttf的文件就行了。包括Quake这样的惊世之作,也都是用的TTF字库。 这样,我们就可以解决点阵汉字的一些问题。通过TTF,我们在字体的质量和字库的数量上获得了暂时性的胜利。 字库的读取和显示 先前谈到点阵字库,只需要很简单的一些操作,就可以显示出想要的汉字。下面我给出一个读取hzk16的函数,它需要一个Surface以供显示用: #include &io.h& #include &stdio.h& #include &conio.h& & // 读取16x16 void 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, &&&&&&&& WORD HzN &&&&&&&& WORD QuH &&&&&&&& WORD WeiH &&&&&&&&
&&&&&&&& BYTE dotBuffer[32];&&&&&&
& &&&&&&&& HzkFp = fopen("HZK16", "rb"); &&&&&&&&
&&&&&&&& HzNum = strlen((const char *)Str)/2; & &&&&&&&& DDSURFACEDESC&&&&&&
&&&&&&&& LPWORD&&&&&&&&&&&&& lpS &&&&&&&& HRESULT&&&&&&&&&&&&
&&&&&&&& ddsd.dwSize = sizeof(ddsd); &&&&&&&&
&&&&&&&& while((ddrval=surf-&Lock(NULL, &ddsd, 0, NULL))==DDERR_WASSTILLDRAWING); &&&&&&&& if(ddrval == DD_OK) &&&&&&&&&&&&&&&&& lpSurface = (LPWORD)ddsd.lpS & &&&&&&&& for(i = 0; i&HzN i++) &&&&&&&& {&&&&&&&
&&&&&&&&&&&&&&&&& QuHao = Str[i*2]-160; &&&&&&&&&&&&&&&&& WeiHao = Str[i*2+1]-160; & &&&&&&&&&&&&&&&&& offset = ((QuHao - 1) * 94 + (WeiHao-1))*32; & &&&&&&&&&&&&&&&&& fseek(HzkFp, offset, SEEK_SET); &&&&&&&&&&&&&&&&& fread(dotBuffer, 32, 1, HzkFp); & &&&&&&&&&&&&&&&&& for(j=0;j&16;j++)
&&&&&&&&&&&&&&&&&&&&&&&&&&& for(k=0;k&2;k++)
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& for(m=0;m&8;m++)
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if(dotBuffer[j*2+k] & Mask[m]) &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& { &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& lpSurface[ddsd.lPitch*(y+j+1) + x+k*8+m] = 0x000000; &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& } &&&&&&&&&&&&&&&&& x+=16; &&&&&&&& } & &&&&&&&& surf-&Unlock(NULL); & &&&&&&&& fclose(HzkFp); } 其实原理很简单: 1.打开字库 2.计算字符串长度(这个函数只支持中文),并且Lock Surface 3.依次计算出每个汉字所对应的区码和位码(汉字的第1个字节是区码,第2个字节就是位码),然后通过公式计算出这个汉字在字库中的偏移量:offset = ((QuHao - 1) * 94 + (WeiHao-1))*32; 4.读出一个32个字节的点阵 5.绘制到Surface上 以上只是16*16点阵字库的显示方法,24*24的读取方法与之类似,大家可以参照相关资料来书写出自己的代码。 & 如何显示TTF字库呢,有很多种手段,下面我按从简单到复杂的的顺序依次介绍: 1.使用Windows API,也就是大家所熟悉的TextOut。通过它,还需要一个HDC(设备句柄),我们就可以随意地在屏幕任何地方显示出文字了。 2.在,有一个FreeType的免费库,而且是OpenSource的。它目前有2个版本:1.0和2.0。其区别在于,1.0只能读取TTF格式的,而2.0支持更多的文件格式,在使用它之前请详细阅读所要遵循的Licence,以下是摘自FreeType2.0对字库的支持列表:
TrueType fonts (and collections)
Type 1 fonts
CID-keyed Type 1 fonts
OpenType fonts (both TrueType and CFF variants)
SFNT-based bitmap fonts
X11 PCF fonts
Windows FNT fonts
3.自己研究TTF的格式,然后自己来操作。晕....... ╮╮    && \█/倒!    && ●虽然我们想要把每一件事情都做好,但是也不是每一件事情都要亲历亲为。如果你非要这样,也行^____^,但是过不了多久,你就会陷入泥沼,到时候你会发现自己的热情正在慢慢被磨灭,什么叫做抓狂,相信你很快就会知道^_^。 & 在有多种选择可以取舍的情况下,我们需要考虑一下,对比一下各种解决方法的优劣。 & 在DirectDraw时代,我们都不自觉地喜欢上了GetDC,因为……多方便啊。可是现在已经到了DirectX8.1时代了(我要使劲地摇那些还沉醉于DirectX7中,为如何在使用alpha时提升那可怜的1、2个fps的朋友们:醒醒,该起床了!),HDC已经被M$列为禁用品。怎么办呢?是的,你可能已经想到了,我们还一直保存着窗口的hWnd呢,可以通过它来得到hdc,从而调用那些需要hdc的API,可是,这样做是更为愚蠢的,这样对你是没有一点好处的,不信,你就试试吧。有一句话,请牢记:要想你的游戏有更快的速度的话,请不要再去碰HDC了。 我们非常清楚hdc是一个超慢的解决办法,它无法在我们的高速游戏中满60分及格。下面来看看FreeType,它更像是一个Service。它的解决方法是,先通过一系列的初始化和设置,告诉FreeType字体的名字和大小等,然后它会动态地申请一个Graphic,再把我们要显示的字画到这个Graphic上,你还可以把它保存为tga格式。不过我们最终所想要的不是这个,所以可能我们还需要从这个Graphic上逐点读取或者用CopyRect,然后再画到我们的画面上。其实它已经是很方便的了,可是需要你去学习如何配置和使用它,这是很花时间的一件事情,而且它最大的优点是可以跨平台,我们需要它吗?如果有一个更为简单的办法,像是如果Textout不是那么慢的话,就好了…… 在这里,顺便谈一下另2个字体显示类:ID3DXFont和CD3DFONT。可能早就有人会说怎么在上面的列表中没有它们?原因我会在下面慢慢地说明: ID3DXFont,它存在于D3DX库中,一个现成的字体类,不过对于它的处理方法……我实在不敢恭维,就引用一位大师所说的话来表达我的看法吧: 在内部实现中, ID3DXFont::DrawText()函数确实做了我上面讨论的工作,先建立一张GDI兼容的位图,把文本绘制到位图上,而后把位图拷贝到纹理贴图上去,最后把纹理渲染到屏幕上。这样你就聚齐了所有的龟速的原始GDI函数,还包括了一大堆的额外开销 — 最终,这个函数比原来GDI的DrawTextEx()函数要慢上超过六倍…… 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)上测试,支持最大大小的Texture。对于这样的硬件不确定性,我们只能取其最小值,也就是256*256。 汉字虽然很多,但是常用的汉字,其实也就只有那么几百个。像这样的字:鬯、鞴,你一辈子会看到多少次呢?如果可以做一个类似于Cache的东西,保存着常用的那些个汉字,在需要显示的的时候,先在Cache中查找,如果有的话,就马上画上去;如果没有,就从字库中提取到Cache中。这样的话,在使用Texture来保存汉字的位图信息的同时,对于每个汉字,我们还要定义一个结构,然后用一个东西把它串起来,综合它们2个,也就实现了我们所要的Cache了。刚开始,我所定义的结构是这样的: struct Char{ & char hz[3];&& // 保存汉字 & // 使用频率 & RECT&&& // 这个字对应位图的区域 & Bool isU // 是否使用 } 对于汉字和英文,我在这里大概地讲一下原理:汉字是由2个字节保存,而英文只需要1个。而判断一个字是否是汉字,只需判断第1个byte是否&128(在原来的GB2312中,汉字的2个字节都是&128的。而新的GBK字库,汉字的第2个字节不一定&128,我想这是扩大了字库容量的原因。我的意思是说,如果给一个字符串你,随机给其中一个位置,然后我问你这个位置是什么?你的回答只能是:1 英文 2 汉字的首字节 3 汉字的尾字节。而这个问题的解法,为了稳妥起见,你必须从字符串的开始判断起)。也就是说在char[3]中,如果保存的是汉字,则char[0]保存汉字第1个字节,char[1]保存汉字第2个字节,第3个存放’\0’;如果是英文的话,则只用到char[0],其它的全部为’\0’。 接下来,对于使用char[3]来保存汉字,是否真的很合适呢?因为如果把它当作一个字符串来看的话,在查找时就需要使用 strcmp 来比较字符串了,这样一定是会影响速度的。如果不把它看作字符串(字符串的最后一个字节需要以’\0’结尾),只用char[2]的话,我们可以只是简单地调用宏MAKEWORD,把2个byte压成1个WORD。当把文字作为一个WORD来看的时候,这样查找比较时可以用WORD内建的==操作,这样要比调用strcmp函数要快得多。 int frequency用来标志每个WORD的使用频率。设想,如果一个字已经存在于Cache中,以后每对它调用一次,就让frequency++。这样做还有一个用意是,是否可以在一个合适的时候,以frequency为参照来对这整个Cache排个序,把常用的字放在前面。那么在显示时,可以先在Cache中查找所要显示的字是否已经存在于Cache中,如果有则直接显示,没有的话才需要采取某种手段将字加入到Cache中。一些常用的字(像:我、的、着、了、过……),使得显示的速度将会大大提高。 其实上面说了半天的Cache,它具体是什么呢?其实就是指的最小绘制单位,在DirectX7里是Surface,而在DirectX8中就是Texture。使用它来存放显示过的汉字,这样,就不用每次都从字库中读取或是调用如TextOut这类GDI超慢的函数了。因为每次在绘制一个文字之前,都会先在这个Cache中找,有的话就直接画上去,没有才会调用TextOut操作。而这样做的原因,我们先设想一下:游戏一般会控制为30fps或是60fps的速度不停地刷新,如果在GameLoop中有任何的代码是龟速级的话,这样就会导致fps的最大数的降低,也就意味着在保证30fps或60fps的同时,能绘制到屏幕上的物体的数量减少了。这就是我们为什么要使用Texture来作为Cache的实现的原因。再一个,文字在屏幕上显示时一般会保持一段时间,这个时间可能是1秒-3秒,我们的游戏也就会相应地更新60fps或180fps,这是因为人们需要阅读它们。或者是一些如标题这样的文字,它们总是不会更新的,或是更新得很慢。我们完全可以在第一时间,比方说我们的画面有60fps,在第1个fps时,我们得知要显示文字”唐”,然后先在Cache中找,结果很糟:没有找到!这时马上用TextOut写到Texture上(现在还是属于第1个fps的时间范围内),而接下来的59个fps(甚至更多),都不用再调TextOut了,而是直接从我们的Cache:Texture上Copy到屏幕上,速度得到了保障。谈到GDI的函数,为了实现设备无关性,它们的速度都很慢。其实它们也不像说得那么慢,如果不是每一帧都要调用它们,也算是蛮快的^_^。那么这个RECT rect,就代表着这个文字所对应在Texture上的区域位置。 使用什么东西来把这n个Char串起来呢,一般会想到的是链表,原因无非有2个:1 随时有新的字加进来,而内存是不连续的 2 它几乎没有容量的限制(除非是内存用完了)。不过链表的访问速度是很慢的,如果使用像数组这样的东西就好了。仔细想想,在这里,我们用来存储的Cache,最大也就是256*256(理由上面说了),所以大小应该会是固定的。我们只需要在数组中的给每一个汉字加上一个标志,说明这个位置的使用情况。那么就使用数组吧,这样的话,访问的速度要更快一些,直接首地址+偏移量就够了,不必像链表,在查找时需要逐node访问。当然,我绝不会想到用new& Char来申请这个数组。因为这样做实在没有必要,请不要过于迷信自己的能力,在STL中已经有vector了,为什么还要自己写呢?^_^最后的一个bool成员变量isUsing,也就是上面所说,用来标志使用情况的。 实际的操作 上面考虑了那么多,我认为都是实际操作之前所应该有的。先谈谈如何显示吧,因为在DirectX8.1中已经将DirectDraw和Direct3D融合为DirectGraphics了。所以无法像原来那样了…………哦,实在有太多东西要讲了,我还是推荐几篇文章给你吧^_^:
接下来,我会假设你已经具备了在DirectX8.1中绘图的基本概念了,所以在你继续往下阅读之前,请务必先仔细阅读以上推荐的文章。 前面提到,需要一个vector来对应Texture上各个位置文字的信息,上面已经创建了一个结构Char,则这个vector的定义为: &&& vector &Char& _vB&&&&&&&&&&&&&& // 记录缓冲中现有的文字情况 首先,由于可以利用硬件的放大缩小机能,所以字体的大小精度要求不是很高,只需要支持16*16和24*24大小的字体就可以了。我们需要一个这样的初始化函数: bool CFont::
/*------------------------------------------------------------- LPDIRECT3DDEVICE8 pd3dDevice& ---& D3DDevice设备 char szFontName[]&&&&&&& & ---& 字体名(如: 宋体) int nSize&&&&&&&&&&&&&&& & ---& 字体大小, 只支持16和24 int nLevel&&&&&&&&&&&&&& & ---& 纹理的大小级别 -------------------------------------------------------------*/ Init( LPDIRECT3DDEVICE8 pd3dDevice, char szFontName[], int nSize, int nLevel )。 & 在DirectX8.1中,由SetTexture(…)所贴的图的大小,也就是Texture的大小,是有大小限制的,长和宽都必须是2^n,而且位图越大,所花费的显存越大,这样留给其他显示用的显存就少了。所以,必须根据需求的不同,来自定Texture(也就是Cache)的大小。因为汉字点阵大小的原因,所以从实用角度而言(比方说只是显示fps或是短小的标题),开辟一个64*64大小的Texture,才能满足最低情况下的需要(这时如果选择16点阵的话可以存放16个汉字,24点阵可以存放7个,依次类推……)。 根据设置,创建Texture: &&& _TextureSize = 32 && nL&&&&&& // 纹理大小 &&& _TextSize& = nS&&&&&&&&&&& // 文字大小 &&& _TextureSize = 32 && nL&&&&&& // 纹理大小 &&&
&&& _RowNum = _TextureSize / _TextS&&& // 计算一行可以容纳多少个文字 &&& _Max = _RowNum * _RowN&&&&&&&&& // 计算缓冲最大值 & 创建字体,还是需要使用Win32 API。也就是先创建一个HDC: &&& _hDc = CreateCompatibleDC(NULL); & 然后创建一个BITMAP和一个FONT,将它们与HDC关联起来。 &&& LOGFONT LogF &&& ZeroMemory( &LogFont, sizeof(LogFont) ); &&& LogFont.lfHeight&&&&&&&& = -_TextS &&& LogFont.lfWidth&&&&&&&&&&&& = 0; &&& LogFont.lfEscapement&&&& = 0; &&& LogFont.lfOrientation&&&&&& = 0; &&& LogFont.lfWeight&&&&&&&& = FW_BOLD; &&& LogFont.lfItalic&&&&&&&& = FALSE; &&& LogFont.lfUnderline&&&&&&&& = FALSE; &&& LogFont.lfStrikeOut&&&&&&&& = FALSE; &&& LogFont.lfCharSet&&&&&&& = DEFAULT_CHARSET; &&& LogFont.lfOutPrecision&&&&& = OUT_DEFAULT_PRECIS;
&&& LogFont.lfClipPrecision&&&& = CLIP_DEFAULT_PRECIS;
&&& LogFont.lfQuality&&&&&&& = DEFAULT_QUALITY; &&& LogFont.lfPitchAndFamily = DEFAULT_PITCH; &&& lstrcpy( LogFont.lfFaceName, szFontName ); &&&
&&& _hFont = CreateFontIndirect( &LogFont ); &&& if ( NULL == _hFont ) &&& { &&&&&& DeleteDC( _hDc ); &&&&&&
(只需要创建一个字体大小的BITMAP即可) &&& BITMAPINFO &&& ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); &&& bmi.bmiHeader.biSize&&&& = sizeof(BITMAPINFOHEADER); &&& bmi.bmiHeader.biWidth&&& &&& = _TextS &&& bmi.bmiHeader.biHeight&&&&& = -_TextS &&& bmi.bmiHeader.biPlanes&&&&& = 1; &&& bmi.bmiHeader.biBitCount = 32; &&& bmi.bmiHeader.biCompression = BI_RGB; &&&
(这里需要定义一个指针指向位图的数据: &&& DWORD *&&&&&& _pB&&&&&&&&&& // 位图的数据指针) & &&& _hBmp = CreateDIBSection( _hDc, &bmi, DIB_RGB_COLORS, &&&&&& (void **) &_pBits, NULL, 0 ); &&& if ( NULL == _hBmp || NULL == _pBits ) &&& { &&&&&& DeleteObject( _hFont ); &&&&&& DeleteDC( _hDc ); &&&&&&
&&& // 将hBmp和hFont加入到hDc &&& SelectObject( _hDc, _hBmp ); &&& SelectObject( _hDc, _hFont ); & 接着设置背景色和文字色: &&& SetTextColor( _hDc, RGB(255,255,255) ); &&& SetBkColor( _hDc, 0 ); & 设置文字为上对齐: &&& SetTextAlign( _hDc, TA_TOP ); & 创建Texture所需要的顶点缓冲: &&& if ( FAILED( _pd3dDevice-&CreateVertexBuffer( _Max * 6 * sizeof(FONT2DVERTEX), &&&&&& D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, &&&&&& D3DPOOL_DEFAULT, &_pVB ) ) ) &&& { &&&&&& DeleteObject( _hFont ); &&&&&& DeleteObject( _hBmp ); &&&&&& DeleteDC( _hDc ); &&&&&&
创建Texture &&& if ( FAILED( _pd3dDevice-&CreateTexture( _TextureSize, _TextureSize, 1, 0,
&&&&&& D3DFMT_A4R4G4B4, D3DPOOL_MANAGED, &_pTexture ) ) ) &&& { &&& &&& DeleteObject( _hFont ); &&&&&& DeleteObject( _hBmp ); &&&&&& DeleteDC( _hDc ); &&&&&& SAFE_RELEASE(_pVB); &&&&&&
&&& } & 设置渲染设备的渲染属性: &&& _pd3dDevice-&SetRenderState( D3DRS_ALPHABLENDENABLE,&& TRUE ); &&& _pd3dDevice-&SetRenderState( D3DRS_SRCBLEND,& D3DBLEND_SRCALPHA ); &&& _pd3dDevice-&SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); &&& _pd3dDevice-&SetRenderState( D3DRS_ALPHATESTENABLE,&&&& TRUE ); &&& _pd3dDevice-&SetRenderState( D3DRS_ALPHAREF,&&&&&&&& 0x08 ); &&& _pd3dDevice-&SetRenderState( D3DRS_ALPHAFUNC,&&&&&&& D3DCMP_GREATEREQUAL ); &&& _pd3dDevice-&SetTextureStageState( 0, D3DTSS_ALPHAOP,&& D3DTOP_MODULATE ); &&&&&&
&&& _pd3dDevice-&SetTexture( 0, _pTexture ); &&& _pd3dDevice-&SetVertexShader( D3DFVF_FONT2DVERTEX ); &&& _pd3dDevice-&SetStreamSource( 0, _pVB, sizeof(FONT2DVERTEX) ); & 设置缓冲的最大容量 &&& _vBuf.resize( _Max ); & 这样,初始化完成了。接下来是如何把一个汉字写到Texture中,以及如何进行管理。定义函数: // 得到文字在纹理中的位置 void CFont:: /*------------------------------------------------------------- char c1&& ---& 文字的第1个字节 char c2&& ---& 文字的第2个字节 int & tX& ---& 写入纹理中的坐标x int & tY& ---& 写入纹理中的坐标y -------------------------------------------------------------*/ Char2Texture( char c1, char c2, int & tX, int & tY ) { &&& WORD w = MAKEWORD(c1, c2);&&&&& // 把此字变为WORD &&& vector&Char&::iterator it = find( _vBuf.begin(), _vBuf.end(), w ); &&& if ( it == _vBuf.end() )&&& // 如果没找到 &&& { &&&&&& it = find( _vBuf.begin(), _vBuf.end(), 0 ); // 查找空闲位置 &&&&&& if ( it == _vBuf.end() ) // 缓冲已满 &&&&&& { &&&&&&&&&& for(; it!=_vBuf.begin(); it-- ) &&&&&&&&&& { &&&&&&&&&&&&& it-&hz = 0; &&&&&&&&&& } //&&&&&&&& Log.Output( "字体缓冲已满, 清空!" ); &&&&&& } & &&&&&& // 计算当前空闲的Char在缓冲中是第几个 &&&&&& int at = it-_vBuf.begin(); & &&&&&& // 得到空闲位置的坐标 &&&&&& tX = (at % _RowNum) * _TextS &&&&&& tY = (at / _RowNum) * _TextS & &&&&&& // 设置这个Char为使用中 &&&&&& (*it).hz = & &&&&&& RECT rect = {0, 0, _TextSize, _TextSize}; &&&&&& char sz[3] = {c1, c2, '\0'}; &&&&&& // 填充背景为黑色(透明色) &&&&&& FillRect( _hDc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH) ); &&&&&& // 往hBitmap上写字 &&&&&& ::TextOut( _hDc, 0, 0, sz, c1 & 0x80 ? 2 : 1 ); &&&&&&
&&&&&& // 锁定表面, 把汉字写入纹理, 白色的是字(可见), 黑色为背景(透明) &&&&&& D3DLOCKED_RECT d3 &&&&&& _pTexture-&LockRect(0, &d3dlr, NULL, D3DLOCK_NOSYSLOCK); &&&&&& BYTE * pDstRow = (BYTE*)( (WORD *)d3dlr.pBits + tY * _TextureSize + tX ); &&&&&&
&&&&&& for (DWORD y=0; y&_TextS y++) &&&&&& { &&&&&&&&&& WORD * pDst16 = (WORD*)pDstR &&&&&&&&&& for (DWORD x=0; x&_TextS x++) &&&&&&&&&& { &&&&&&&&&&&&& BYTE bAlpha = (BYTE)((_pBits[_TextSize * y + x] & 0xff) && 4); &&&&&&&&&&&&& if (bAlpha & 0) &&&&&&&&&&&&&&&&& *pDst16++ = (bAlpha && 12) | 0x0 &&&&&&&&&&&&& else &&&&&&&&&&&&&&&&& *pDst16++ = 0x0000; &&&&&&&&&& } &&&&&&&&&& pDstRow += d3dlr.P &&&&&& } &&&&&& _pTexture-&UnlockRect( NULL ); &&& } &&& else &&& { &&&&&& // 计算当前空闲的Char在缓冲中是第几个 &&&&&& int at = it-_vBuf.begin(); & &&&&&& // 得到这个字的坐标 &&&&&& tX = (at % _RowNum) * _TextS &&&&&& tY = (at / _RowNum) * _TextS &&& } } 以上代码中的注释已经很清楚了,相信无须我多言。这里唯一需要声明的是:原来所定义的Char结构是这样的 struct Char{ & char hz[3];&& // 保存汉字 & // 使用频率 & RECT&&& // 这个字对应位图的区域 & Bool isU // 是否使用 } 后来因为将char hz[3]合成为WORD,所以改为WORD hz。然后对于int frequency,这个词频应该如何表现,我一直没有想到很好的方法。frequency应该在何时++呢?是在每次被使用的时候吗?但是这样的话,上面说过,游戏是以60fps的速度在刷新,如果停上1分钟的话,变量很快就会溢出了。就算是使用像是DWORD或__int64这样的巨型变量保存,也是不安全的。除非能在某个合适的时候将frequency清零,但是这个“时候”是什么时候呢?或者设置一个最大值,如65535,但是这样也基本上没什么用途,很快,所有在vector中的Char中的frequency都会++成65535的。回忆一下最初,是因为想把常用字放到vector的前面,以便每次find操作可以最快返回结果的。而经过我的测试,即使不做这样的优化操作,速度也是很快的,毕竟Cache不是很大,加上vector是连续内存空间。所以可以放弃使用int frequency。 然后对于RECT rect,因为没有了int frequency,意味着一旦将汉字写入到Texture,其位置就不会变动了。所以,很容易根据find函数操作后的iterator,直接计算出这个汉字所在Texture的位置。这样,RECT rect也不再必须。 而bool isUsing,它本身就是个鸡肋,要也可以,这样结构更加清晰。不过,直接通过观察WORD hz为0或非0,即可实现isUsing的作用了。 为什么要对结构Char这么精雕细琢呢? 1.既然没有必要的东西,就应该删除 2.Char结构的大小越大,vector所要求的内存越大 3.小的结构,find可以更快地查找出所结果 为什么find会正常工作呢?这里我要大概地讲一下find是如何查找出所需的位置的:它只是简单地使用while从vector的begin一直遍历到end,逐个判断,直到找到为止。find要求必须实现自己的operator ==(),进一步跟踪到find的源码中,发现也是这样。于是前面的结构Char变成了现在这样: && struct Char{ &&&&&& WORD&& &&&&&&&&&& // 文字 & &&&&&& Char() : hz(0) {} & &&&&&& // 用作查找文字 &&&&&& inline bool operator == ( WORD h ) const &&&&&& { &&&&&&&&& return hz==h ? true : &&&&&& } && }; 是不是很简单?^___^ & 终于到了显示的函数了: // 得到文字在纹理中的位置 bool CFont:: /*------------------------------------------------------------- char szText[]& ---& 显示的字符串 int x&&&& && ---& 屏幕坐标x int y&&&& && ---& 屏幕坐标y D3DCOLOR& && ---& 颜色及alpha值 int nLen& && ---& 字符串长度 float fScale&& ---& 放大比例 -------------------------------------------------------------*/ TextOut( char szText[], int x, int y, D3DCOLOR color, int nLen, float fScale ) { && Assert( szText!=NULL ); & && float sx = x, sy = y, &&&&&& & offset=0, w=0, h=0, tx1=0, ty1=0, tx2=0, ty2=0; && w = h = (float)_TextSize * fS & && char ch[3] = {0,0,0}; && FONT2DVERTEX * pVertices = NULL; && UINT wNumTriangles = 0; && _pVB-&Lock(0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD); & && if ( -1 == nLen ||&&&&&& &&&&&& // 默认值-1 &&&&&& &nLen & lstrlen( szText ) ) // 如果nLen大于字符串实际长度, 则nLen=实际长度 &&&&&& nLen = lstrlen( szText ); && for (int n=0; n&nL n++ ) && { &&&&&& ch[0] = szText[n]; & &&&&&& if ( ch[0]=='\n' ) &&&&&& { &&&&&&&&& sy+=h; &&&&&&&&& sx=x; &&&&&&&&&
&&&&&& } & &&&&&& if ( ch[0] & 0x80 ) &&&&&& { &&&&&&&&& n++; &&&&&&&&& ch[1] = szText[n]; &&&&&&&&& offset = &&&&&& } &&&&&& else &&&&&& { &&&&&&&&& ch[1] = '\0'; &&&&&&&&& offset = w / 2 ; &&&&&& } & &&&&&& int a, &&&&&& Char2Texture( ch[0], ch[1], a, b ); &&
&&&&&& // 计算纹理左上角 0.0-1.0 &&&&&& tx1 = (float)(a) / _TextureS && &&& ty1 = (float)(b) / _TextureS &&&&&& // 计算纹理右上角 0.0-1.0 &&&&&& tx2 = tx1 + (float)_TextSize / _TextureS && &&& ty2 = ty1 + (float)_TextSize / _TextureS & &&&&&& // 填充顶点缓冲区 &&&&&& *pVertices++ = FONT2DVERTEX(sx,&&& sy + h, 0.9f, color, tx1, ty2); &&&&&& *pVertices++ = FONT2DVERTEX(sx,&&& sy,&&& 0.9f, color, tx1, ty1); &&&&&& *pVertices++ = FONT2DVERTEX(sx + w, sy + h, 0.9f, color, tx2, ty2); &&&&&& *pVertices++ = FONT2DVERTEX(sx + w, sy,&&&&&& 0.9f, color, tx2, ty1); &&&&&& *pVertices++ = FONT2DVERTEX(sx + w, sy + h,&& 0.9f, color, tx2, ty2); &&&&&& *pVertices++ = FONT2DVERTEX(sx,&&& sy,&&& 0.9f, color, tx1, ty1); & && &&& wNumTriangles+=2; & &&&&&& sx+=&& // 坐标x增量 && } && _pVB-&Unlock(); && _pd3dDevice-&DrawPrimitive( D3DPT_TRIANGLELIST, 0, wNumTriangles ); & &&
} 结束语 记得有一句名言: Keep it simple and stupid.在实现功能的同时,保持代码简单、清晰是非常重要的一件事。相信在往后的日子里,在不论是别人阅读或是你自己回顾的时候,你都会发现一如既往地遵守这个守则,是多么得重要! 相信通过上面我那无数的废话,加上代码中还算足够的注释,聪明的你一定能够明白这其中的原理了吧。如果以上的内容还不足以让你完全搞清楚的话,你可以登录我的主页:
上面不仅包括了上面所写的程序代码,还有一个用来演示效果的一个很简单的demo。 说明,以上所实现的CFont是包含在我的游戏引擎中的一个部件,而目前已经实现的部件包括有: 1.CGameFrame(游戏框架类)& -----& 封装了窗口及D3D设备的建立,需要派生出自己的子类 2.CAudio和CSound(声音类) -----& 支持wav/mid/mp3的播放 3.CDirectInput(控制类)&&& -----& 键盘、鼠标操作 4.CDirectShow(视频类)&&&& -----& 支持avi/mpg/mov等的播放 5.CSpriteX(精灵类)&&&&&&& -----& 方便游戏中对精灵的控制 6.CFont(字体类)&&&&&&&&&& -----& 中英文字体的显示 7.CTimer(时间类)&&&&&&&&& -----& 高精度时间的控制 8.FPS(fps 类)&&&&&& &&&&& -----& fps的计算 9.LOG(日志类)&&&&&&&&&&&& -----& 游戏中的错误反应以及状态记录 最重要的是,这个Game Engine完全是开放源代码的。关于更新的情况、版本说明以及源码下载,请随时关注我的主页! 接下来,我将会继续完善这个Engine,可能加入的有:高效粒子系统、斜45度角地图……我最擅长从零开始创造世界,所以从来不怕失败,它最多也就让我一无所有。
TA的最新馆藏
喜欢该文的人也喜欢}

我要回帖

更多关于 真的汉子游戏第六关 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信