数据结构在游戏中的简单应用.doc_第1页
数据结构在游戏中的简单应用.doc_第2页
数据结构在游戏中的简单应用.doc_第3页
数据结构在游戏中的简单应用.doc_第4页
数据结构在游戏中的简单应用.doc_第5页
已阅读5页,还剩2页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

数据结构在游戏中的简单应用/Program/Control/datastruct.htm作者:源代码之光 | 日期:2005-07-26 在游戏的编写中,不可避免的出现很多应用数据结构的地方,有些简单的游戏,只是由几个数据结构的组合,所以说,数据结构在游戏编程中扮演着很重要的角色。本文主要讲述数据结构在游戏中的应用,其中包括对链表、顺序表、栈、队列、二叉树及图的介绍。读者在阅读本文以前,应对数据结构有所了解,并且熟悉C/C+语言的各种功用。好了,现在我们由链表开始吧!1、链表在这一节中,我们将通过一个类似雷电的飞机射击游戏来讲解链表在游戏中的应用。在飞机游戏中,链表主要应用在发弹模块上。首先,飞机的子弹是要频繁的出现,消除,其个数也是难以预料的。链表主要的优点就是可以方便的进行插入,删除操作。我们便将链表这一数据结构引入其中。首先,分析下面的源代码,在其中我们定义了坐标结构和子弹链表。struct CPOINTint x;/ X轴坐标int y;/ Y轴坐标;struct BULLETstruct BULLE* next;/ 指向下一个子弹CPOINT bulletpos;/ 子弹的坐标int m_ispeed;/ 子弹的速度;接下来的代码清单是飞机类中关于子弹的定义:class CMYPLANEpublic:void AddBullet(struct BULLET*);/ 加入子弹的函数,每隔一定时间加弹void RefreshBullet();/ 刷新子弹privated:struct BULLET *st_llMyBullet;/ 声明飞机的子弹链表;在void AddBullet(struct BULLET*)中,我们要做的操作只是将一个结点插入链表中,并且每隔一段时间加入,就会产生连续发弹的效果。这是加弹函数主要的源代码:void AddBullet(struct BULLET*)struct BULLET *st_llNew,*st_llTemp;/ 定义临时链表st_llNew=_StrucHead; / 链表头(已初始化)st_llNew-(BULLET st_llMyBullet *)malloc(sizeof(st_llMyBullet);/ 分配内存st_llTemp= =_NewBullet;/ 临时存值st_llNew-next=st_llTemp-next; st_llTemp-next=st_llNew;函数Void RefreshBullet()中,我们只要将链表历遍一次就行,将子弹的各种数据更新,其中主要的源代码如下:while(st_llMyBullet-next!=NULL)/ 查找st_llMyBullet-bulletpos.x-=m_ispeed;/ 更新子弹数据st_llMyBullet=st_llMyBullet-next; / 查找运算经过上面的分析,在游戏中,链表主要应用在有大规模删除,添加的应用上。不过,它也有相应的缺点,就是查询是顺序查找,比较耗费时间,并且存储密度较小,对空间的需求较大。如果通过对游戏数据的一些控制,限定大规模的添加,也就是确定了内存需求的上限,可以应用顺序表来代替链表,在某些情况下,顺序表可以弥补链表时间性能上的损失。当然,应用链表,顺序表还是主要依靠当时的具体情况。那么,现在,进入我们的下一节,游戏中应用最广的数据结构 顺序表。2、顺序表本节中,我们主要投入到RPG地图的建设中,听起来很吓人,但是在RPG地图系统中(特指砖块地图系统),却主要使用数据结构中最简单的成员 顺序表。我们规定一个最简单的砖块地图系统,视角为俯视90度,并由许多个顺序连接的图块拼成,早期RPG的地图系统大概就是这样。我们这样定义每个图块:struct TILE/ 定义图块结构int m_iAcesse;/ 纪录此图块是否可以通过/ 其中有每个图块的图片指针等纪录;当m_iAcesse=0,表示此图块不可通过,为1表示能通过。我们生成如下地图:TILE TheMapTile105;并且我们在其中添入此图块是否可以通过,可用循环将数值加入其中,进行地图初始化。如图表示:0 1 2 3 4 5 6 7 8 90 1 1 1 1 1 1 1 1 1 11 0 0 0 0 0 1 1 1 1 02 0 0 0 0 0 1 1 1 1 03 0 0 0 0 0 1 1 1 1 04 1 1 1 1 1 1 1 1 1 1图1从上图看到这个地图用顺序表表示非常直接,当我们控制人物在其中走动时,把人物将要走到的下一个图块进行判断,看其是否能通过。比如,当人物要走到(1,0)这个图块,我们用如下代码判断这个图块是否能通过:int IsAcesse(x,y)return TheMapTilex,y.m_iAcesse;/ 返回图块是否通过的值上述只是简单的地图例子,通过顺序表,我们可以表示更复杂的砖块地图,并且,现在流行的整幅地图中也要用到大量的顺序表,在整幅中进行分块。好了,现在我们进入下一节:3、栈和队列栈和队列是两种特殊的线性结构,在游戏当中,一般应用在脚本引擎,操作界面,数据判定当中。在这一节中,主要通过一个简单的脚本引擎函数来介绍栈,队列和栈的用法很相似,便不再举例。我们在设置脚本文件的时候,通常会规定一些基本语法,这就需要一个解读语法的编译程序。这里列出的是一个语法检查函数,主要功能是检查“()”是否配对。实现思想:我们规定在脚本语句中可以使用“()”嵌套,那么,便有如下的规律,左括号和右括号配对一定是先有左括号,后有右括号,并且,在嵌套使用中,左括号允许单个或连续出现,并与将要出现的有括号配对销解,左括号在等待右括号出现的过程中可以暂时保存起来。当右括号出现后,找不到左括号,则发生不配对现象。从程序实现角度讲,左括号连续出现,则后出现的左括号应与最先到来的右括号配对销解。左括号的这种保存和与右括号的配对销解的过程和栈中后进先出原则是一致的。我们可以将读到的左括号压入设定的栈中,当读到右括号时就和栈中的左括号销解,如果在栈顶弹不出左括号,则表示配对出错,或者,当括号串读完,栈中仍有左括号存在,也表示配对出错。大致思想便是这样,请看代码片断:struct/ 定义栈结构int m_iData100;/ 数据段int m_iTop;/ 通常规定栈底位置在向量低端SeqStack;int Check(SeqStack *stack)/ 语法检查函数char sz_ch;int boolean; Push(stack,# );/ 压栈,#为判断数据sz_ch=getchar();/ 取值boolean=1;while(sz_ch!=n&boolean)if(sz_ch= =()Push(stack,ch);if(sz_ch= =)if(gettop(stack)= =#) / 读栈顶boolean=0;elsePop(stack); / 出栈sz_ch=getchar();if(gettop(stack)!=#) boolean=0;if(boolean) coutright; / 输出判断信息elsecouterror;这里只是介绍脚本的读取,以后,我们在图的介绍中,会对脚本结构进行深入的研究。总之,凡在游戏中出现先进后出(栈),先进先出(队列)的情况,就可以运用这两种数据结构,例如,帝国时代中地表中间的过渡带。4、二叉树树应用及其广泛,二叉树是树中的一个重要类型。在这里,我们主要研究二叉树的一种应用方式:判定树。其主要应用在描述分类过程和处理判定优化等方面上。在人工智能中,通常有很多分类判断。现在有这样一个例子:设主角的生命值d,在省略其他条件后,有这样的条件判定:当怪物碰到主角后,怪物的反应遵从下规则: 表1根据条件,我们可以用如下普通算法来判定怪物的反应:if(d100) state=嘲笑,单挑;else if(d200) state=单挑;else if(d300) state=嗜血魔法;else if(d=200)&(d=300)&(d=100)&(d200) state=单挑;else if(d100) state=嘲笑,单挑;else state=逃跑;通过计算,两种算法的效率大约是2:3,很明显,改进的算法在时间性能上提高不少。一般,在即时战略游戏中,对此类判定算法会有较高的时间性能要求,大家可以对二叉树进行更深入的研究。现在,我们进入本文的最后一节:图的介绍,终于快要完事了。5、图在游戏中,大多数应用图的地方是路径搜索,即关于A*算法的讨论。由于介绍A*算法及路径搜索的文章很多,这里介绍图的另一种应用:在情节脚本中,描述各个情节之间的关系。在一个游戏中,可能包含很多分支情节,在这些分支情节之间,会存在着一定的先决条件约束,即有些分支情节必须在其他分支情节完成后方可开始发展,而有些分支情节没有这样的约束。通过分析,我们可以用有向图中AOV网(Activity On Vertex Network)来描述这些分支情节之间的先后关系。好了,现在假如我们手头有这样的情节:情节编号情节先决条件C1遭遇强盗无C2受伤C1C3买药C2C4看医生C2C5治愈C3,C4注意:在AOV网中,不应该出现有向环路,否则,顶点的先后关系就会进入死循环。即情节将不能正确发展。我们可以采取拓扑派序来检测图中是否存在环路,拓扑排序在一般介绍数据结构的书中,都有介绍,这里便不再叙述。那么以上情节用图的形式表现为(此图为有向图,先后关系在上面表格显示): 图3现在我们用邻接矩阵表示此有向图,请看下面代码片断:struct MGRAPHint VexsMaxVex;/ 顶点信息int ArcsMaxLenMaxLen;/ 邻接矩阵;顶点信息都存储在情节文件中。将给出的情节表示成邻接矩阵:0 1 0 0 00 0 1 1 00 0 0 0 10 0 0 0 10 0 0 0 0图4我们规定,各个情节之间有先后关系,但没有被玩家发展的,用1表示。当情节被发展的话,就用2表示,比如,我们已经发展了遭遇强盗的情节,那么,C1与C2顶点之间的关系就可以用2表示,注意,并不表示C2已经发展,只是表示C2可以被发展了。请看下面的代码:class CRelationpublic:CRelation(char *filename); / 构造函数,将情节信息文件读入到缓存中void SetRelation(int ActionRelation);/ 设定此情节已经发展BOOL SearchRelation(int ActionRelation); / 寻找此情节是否已发展BOOL SaveBuf(char *filename);/ 保存缓存到文件中privated:char* buf; / 邻接矩阵的内存缓冲;在这里,我们将表示情节先后关系的邻接矩阵放到缓冲内,通过接口函数进行情节关系的修改,在BOOL SearchRelation(int ActionRelation)函数中,我们可以利用广度优先搜索方法进行搜索,介绍这方面的书籍很多,代码也很长,在这里我就不再举例了。我们也可以用邻接链表来表示这个图,不

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论