Space Demon第一阶段总结文档

    Space Demon,也就是我说的重做《雷电Kevin Lynx》,从2月1号开始,到今天2月8号,写了8000行代码。不过还是没完成,根我预想的还有很大差距。目前我必须得回家了,家里没电脑,只能中断开发了。

  写了分总结文档,方便假期回来后继续开发:

                            Space Demon第一阶段总结文档

 

作者:Kevin Lynx

日期: 2007-2-8

 

第一部分:系统类图(忽略细节精灵关系):

 

其中:

CMainGUIMgrCGameWidget保存有SpaceDemonApp对象指针;其他大部分被CGameWidget所拥有的对象都保存有CGameWidget对象的指针。其获得方法都是:当创建一个子对象时,就把自身的this指针传过去。在这里,我们把这些对象的关系抽象为父子关系。例如CGameWidget包含一个CLevelMgr对象,那么就称CGameWidget对象是CLevelMgr对象的父对象,CLevelMgrCGameWidget对象的子对象。把父对象的指针给该对象的每一个子对象,是因为,有时候一个子对象会用到其兄弟对象。而为了方便,就把父对象指针给其子对象,子对象要用其兄弟对象时,就通过其父对象来获得。

 

CLevelMgr 负责管理载入关卡,载入关卡的时候会根据关卡信息来调用CEnemyPlaneMgr创建敌机。CLevelMgr还负责游戏中背景效果的处理。

 

CEffectMgr 负责游戏中所有特效的管理,这些特效包括帧动画特效(例如帧动画爆炸),粒子系统特效(一般是爆炸效果)。CEffectMgr还负责保存一个粒子系统特效集合(目前还没有帧动画特效)。当外部世界要CLevelMgr创建一些特效时,CLevelMgr就从该集合里取特效样本出来创建。

CParticleFX 代表一个粒子系统特效。CEffectMgr使用一个容器来保存很多CParticleFX对象。

 

其他的很多manager都会用一个容器来管理其子对象。例如CBulletMgr, CEnemyPlaneMgr, CBonusMgr等。

 

第二部分:精灵系统类图:

 

       这里,我提出了一个“精灵资源管理器”的概念!这是一种分而治之的思想,我也称之为“插件式”思想。其提出动机为:当游戏中有很多资源时,我们除了要管理各种资源的载入释放等,往往还要对资源进行二次加工。例如对于一个敌机精灵的帧动画资源,其所有帧都可能在一张图片上。而资源管理器往往只会负责载入这幅图片,如果让这种精灵在渲染时计算哪一帧位置,则只会把代码结构弄混乱,并且灵活性也不好,因为一旦换了图片,就很有可能修改代码。

       因此,这里,为了提供一个资源加工器,我为每一个精灵加入了“精灵资源管理器”,而为了更灵活地配置资源,我又为每一个精灵配置一个外部的XML文件。该文件起初只是为了描述该精灵的资源加工方式,好让精灵资源管理器灵活地加工资源。后来,我发现每一个精灵除了资源外,还包含一些其他需要初始化的属性,于是,XML文件里除了描述精灵资源数据外,还描述了精灵的一些初始属性。这样,在很多程度上就减少了程序中常量的数量,很多时候要实验一个数据取哪个值时更为合适,就没必要再重新编译程序了。

       这里我们看到,精灵资源管理器是属于每一种具体的精灵的!每一个精灵对象没必要单独拥有一个精灵资源管理器,精灵资源管理器负责的是这一类精灵的资源管理。而不是具体精灵的对象则不能拥有一个精灵资源管理器,因为这类对象根本没有具体的外观。例如精灵基类,它是抽象的,不是具体的,不存在具体的形态,也就没有具体的外观,所以没必要。

       于是,精灵管理器理所当然地成为每一类具体精灵的静态成员对象。

 

       精灵资源管理器最显著的特征就是会保存一个精灵每一帧在图片上的矩形位置。因此,在渲染精灵时,只需要指定这个矩形变量即可。于是,我发现,每个精灵在渲染时代码都是一样的。于是,这里就可以把这些一样的代码放进他们的基类里。但是,这里需要一个精灵管理器对象。如果把代码放进基类,这个精灵管理器从何而来?注意,这里不能让精灵基类直接拥有一个精灵资源管理器!

       于是,出于精简代码的目的,我为精灵基类添加了一些默认的处理代码。而具体的精灵类,它的接口保留,但是接口的代码则移到了精灵基类的那些默认处理代码里。而这些接口呢?它们只起到一个桥梁的作用!即,外部世界依然调用这些接口,这些接口则转调用精灵基类的那些默认处理代码。------这是第二步优化。

       再后来,我进行了第三步优化。也就是提供的那些派生于精灵基类的模板类tDefaultBonus等。(这可以参看另一分文档)这里用到了一个看上去很古怪的技巧。

       这些模板类都提供了一些默认的处理方法,即转调用基类的默认处理代码。

       但是,有时候,我们可能要创建一些不使用默认方法的精灵。这个时候就可以不使用这个提供默认处理方法的模板,而是直接派生。于是,就出现了类似于这样的继承关系:

 

关键技术罗列:

1.  精灵资源管理器,使得管理游戏资源更为容易。组件化的思想使得程序可以轻松管理更多的资源。

2.  XML文件配置各种精灵的资源数据,各种精灵的常量属性以及初始属性。使得游戏调整整体规则更为容易,效率也大幅度提升。

3.  独特的模板化技术,泛化了代码,却不依赖于提供的类型参数。这里的模板提供了一种默认的精灵初始化,逻辑更新,以及渲染方法。并独特地使用语言本身的数据类型来标识不同的精灵类。(详见tDefaultBullet, tDefaultBonus, tDefaultEnemy类)

4.  独特地分离了敌机类的AI代码,使得AI系统完全插件化。同一外观的敌机,可以有不同的AI。但是,有时候AI代码还需要专门为调用此函数的精灵保存一些数据。于是,普通的函数就难以胜任。顺理成章地,我使用了仿函数(即函数对象,functor)。

 

要扩展敌机的AI,只需要加入AI函数对象,以及修改关卡数据文件即可。

 

5.  声音处理上为了实验audiere库,我没有使用引擎本身使用的BASS库(或FMOD库),我模仿Popcap Framework的资源脚本文件,写了自己的声音资源管理器。(事实上这一点不难)

 

为了改善audiere不能在一个声音播放完之前再次重叠播放此声音的缺陷(事实上这本来就是不可能的,一种声音对应一个 channel,不同声音才能对应不同的channel),我在加载声音(sound,对于music没这个必要)时,创建了多个声音副本,当播放此声音时,我会在这个声音的所有副本中寻找没有播放的来播放。这样,因为每一个副本事实上虽然听起来一样,但是其播放时会占用不同的channel,这就实现了同一种(听起来相同)声音的重叠播放。

 

 

对于XML配置文件格式的说明(方便后期调整游戏系统):

1.  所有精灵所共有的属性:

例如:

<BonusBomb imageId="BONUS" frameCount="10" w="27" h="50" vx="2" vy="1" bonusData="5" comSndId="SND_BONUS_BOMB">

     <ColAll colNum="1" >

         < Col startX="0" startY="382" count="10" />

     </ColAll>

     <StatusAll count="1">

         <Status dir="KEEP_CENTER" action=" NORMAL " startFrame="0" endFrame="9" delay="10" times="-1" />

     </StatusAll>

     <CollisionCheckRect x="0" y="0" w="26" h="35" />

</BonusBomb>

 

根节点<BonusBomb>只是用来方便辨认此文件,其不会影响程序读取;

根节点的一些属性:

imageId 该精灵所使用的图片资源ID号,该ID总是对应于resources.xml中的资源IDresource.xml是引擎本身使用的资源脚本文件。

frameCount:该精灵的帧动画总共有多少帧。

w:该精灵帧动画每一帧的图片宽度,注意是图片宽度。

h:该精灵帧动画每一帧的图片高度; w,h主要用于让精灵资源管理器从指定的图片上读取出每一帧所对应的图片上的矩形区域。

vx, vy :精灵X方向和Y方向上的速度常量。该常量会被用于设置精灵某一时刻的速度。

bonusData:是宝物的特有数据,它不是所有精灵的共有属性。

comSndIdcommon sound id,事实上每一个精灵我都为其分配了一个这样的声音ID。该ID对应的是声音资源管理器里的声音ID。也就是sound_res.xml 里定义的ID

customRect:可选属性,它表示精灵每一帧的在图片上的矩形区域是由程序自动计算还是由用户自己定义。如果该属性为0或者没有,则由程序自己计算;如果指定为1,则用户需要在XML文件CollisionCheckRect块后自己定义每一帧的矩形区域。这主要是出于某些精灵图片区域不规则的原因而考虑的(图片质量不高)

 

ColAll块的一些属性:

colNum:表示精灵在其对应的图片上占有几行,整个colAll块都被用于精灵管理器定位每一帧在图片上的矩形区域

<Col>startX, startY, count:每一行的起始位置,以及该行有多少帧。

 

StatusAll块的一些属性:

该块主要描述了精灵各种状态的动画信息,方便设置该精灵的动画状态。

count 表示该精灵共有多少种动画状态。

其下就对应每一种状态的数据:dir表示方向,action表示动作,startFrame表示该种状态的起始帧;endFrame,该状态的结束帧,delay:该状态的帧变化速度,值越小动画越慢,times:该状态播放次数,为-1表示循环播放。

 

ColCheckRect 块表示碰撞检测数据,XY表示碰撞检测区域左上角坐标与其图片左上角坐标的偏移,WH表示碰撞检测宽度和高度。

 

2.  宝物的特有数据:

bonusData:该数据在不同的宝物中,其表示意义是不一样的,对于rocket, lightning之类的,往往表示使用次数;而对于defense, double_attack则往往表示时间。

 

3.  子弹的特有数据:

 up :描述该子弹在图片外观上是向下的还是向上的,因为同一个子弹,如果由主角发射,则其外观应该是向上的,而对于敌机发射,则需要是向下的。该数据为1则表示该子弹在图片外观上是向上的。

 evy:描述该子弹被敌机发射时其纵坐标速度大小。这主要考虑到运动速度的相对大小问题(相对于背景卷动)

 hurtValue :描述该子弹的攻击力,当飞机被该子弹击中时,飞机会根据该值来减少HP

 

4.  飞机的共有数据(敌机和主角):

fireDelayTime:表示该敌机每次发射子弹的时间间隔,值越大,其间隔就越大。

expId:爆炸效果的ID号,对应于CEffectMgr中的爆炸效果集合中的元素

smallExpId:小爆炸效果的ID号,当飞机没死亡而受到攻击时播放此效果

impact:飞机的撞击力。撞击力会决定敌机与主角相撞时各自减少的HP量,该值也决定了该飞机死亡时屏幕震动的强度。

 

5.  敌机的特有数据:

addScore:当该敌机被主角击毁后,该敌机给主角增加的分数

hp:该敌机的生命值

 

6.  主角的特有数据:

energyLevel:即主角初始时的生命总值(可死亡次数)

eneryPerLev:每个能量等级的能量,其实也就是每一次生命的HP

startFireLevel:初始时的开火等级,可取1----55个数。

 

7.关于声音资源配置文件,该文件分为两个块:Sound , Music。凡是是声音sound的,就放在Sound块,是音乐的,就放在music块。每一个数据都有一个可选项:defaultVol,表示该声音的初始音量。可以不设置。

 

你可能感兴趣的:(游戏,xml,文档,action,delay,functor)