现在的位置: 首页 > 综合 > 正文

重做雷电kevin lynx版—真正为了游戏,而不是练习程序

2013年09月18日 ⁄ 综合 ⁄ 共 3842字 ⁄ 字号 评论关闭

打算重做一个飞机设计类游戏。这次没有连续的时间。但是,我想慢慢地磨出一个我喜欢的作品。而不是象以前那样以death match的方式快速开发。

这里先总结一下一个飞机设计类游戏(例如经典的雷电)所拥有的特性:

1.游戏主体部分(去处GUI等杂项)包括:主角飞机,敌机,敌机子弹,主角子弹,宝物,各种特效,关卡,关卡中的各种景物(其实也可以当做敌机)

2.各种敌机的AI。敌机的AI不但是单个的,有时候为了实现整体效果,看上去敌机还会考虑到它周围的其他敌机。例如一排敌机以螺旋的轨迹运动。事实上也许规划好每个敌机的行为,就可以在不考虑其周围环境的情况下独自AI,而可以造成总体看上去有规律的移动效果。

 

       3.各种子弹看上去有AI,但其实完全可以把子弹以粒子系统的思想来处理。即为其赋予一定的速度,加速度,角速度,等等之类。就可以实现各种子弹效果。即使是有规律的一群子弹,也可以按照这种思想来实现。

 

       4.各种特效,各种粒子系统。我想在特效上应该会比雷电漂亮。

 

       5.地图中什么时候出现敌机,出现哪种敌机,这些都应该在地图信息里被安置好。这次将不再采取实时读取的方式,而是在游戏载入一个关卡(地图,以后将统称为关卡)时就创建好所有敌机。当敌机该出现时,就让其active

              哪架敌机会爆出宝物,也应该是放置在关卡信息文件中。这些信息将用于创建敌机时赋予敌机本身属性。

 

       6.各种宝物,其实也应该有其AI,用来决定其运动方式。默认的AI是在空中漂浮一段时间后漂出游戏区域,然后消失。

 

       7.关卡地面(如果是在地面上空飞行)上的景物无论是否影响主角飞机,都不会与主角发生碰撞检测,但是其发射的子弹要参与检测。主角发射的子弹要与景物参与碰撞检测。

          景物有可能不止一层。有可能需要多层景物。这就需要为每一个景物(包括敌机)设置一个层次值。

 

       8.各种需要实现的特效,包括:

              1)。拖着尾烟的导弹,即尾烟效果

              2)。飞机中弹时的闪烁效果(设置其渲染颜色即可)

              3)。全屏振动效果

 

 

 

 

       更多特性继续添加。。。

 

       在程序上,我要达到的目标:

1.  让尽可能多的属性由外部脚本文件(如XML文件)来配置

2.  尽可能地把所有对象都模块化插件化,插件化即为当少了这个“插件”时,程序可以运行,多了这个插件时,又可以很容易地加进主体部分并起作用。尽量减少模块的偶合程度!

3.  资源处理上尽可能做到脚本化。

 

 

 

 

 

 

 

具体的一些讨论:

特效的实现:

1.  全屏震动效果:可以简单地移动背景图的贴图位置。

2.  尾烟效果:也许可以用图象拉伸的技巧实现。

 

架构的一些技巧:

如何实现这里说的“插件化”?

先看一下,假如用我以前的设计方法,会弄成什么样子。

对于所有敌机的管理,我会设计一个敌机管理类;对于所有敌机子弹,我会设置一个敌机子弹管理类;对于所有主角子弹,我会设置一个主角子弹管理类;对于所有宝物,我会设置一个所有宝物的管理类;对于所有特效,我会设置一个所有特效管理类。然后顶层再加一个游戏管理器(CGame,主要的Manager),它就只需要拥有这所有的manager即可。游戏管理器要更新所有物体的逻辑时,会调用每个managerUpdate函数,然后 manager 又遍历其所有管理的物体的Update函数。同理,游戏管理器要渲染所有物体,也只需要调用每个ManagerRender 函数,然后每个manager再遍历其管理的所有物体,分别调用其每个物体的Render函数。这样的层次关系,就可以使顶层管理非常简单。顶层游戏管理器就不需要去关心一架敌机如何更新自己之类的事务!

       这样的设计确实不错。这种方法已经在我的几个游戏里用到,被作为整体架构。

       但是,这里有一些细节问题:

       其一,

很显然,所有不同类型的敌机都需要从一个基类敌机类派生。然后敌机管理器内部的容器类型就是这个基类类型。只要基类规定好接口,就可以让敌机管理器实现对所有不同类型敌机的管理。最重要的,创建一种敌机的代码不应该放在敌机管理器内部! 因为这样的话,每一次我增加一种新类型的敌机时,除了增加这种敌机的头文件和实现文件外,敌机管理器内部还要修改创建敌机代码(当然还需要包含新敌机描述的头文件)。当然可以再加一个敌机生成工厂(工厂模式),但是同样就需要修改其代码。这里的改进方式在《面向对象游戏开发》一书里有提到过,那就是让每一种敌机都包含创建自己的代码!然后敌机管理器有一个注册接口。每一次新增加一种敌机时,就象敌机管理器注册。然后敌机管理器要创建该敌机时,就调用该敌机的创建接口创建其自身。这样,就不需要再去修改敌机管理器的代码(当然包含新敌机的描述头文件是必须的,包含在实现文件的话,编译时间只会增加编译一个CPP文件的时间)

       同理,各种管理器都应该使用这种方法。每一种敌机都有其自己特有的敌机子弹(有可能有多种,BOSS就有多种);主角也有多种类型的子弹;宝物也有多种;特效也有多种。

 

       这样,就可以把整个工程分为两大部分:一部分作为核心部分(core),该部分包含各种manager,以及各种对象的基类;另一部分为扩展部分,各种具体的敌机,敌机子弹,主角子弹,宝物都在这里面。

      

       其二,

       资源管理部分,可以使用Popca自身的资源模块来管理资源。一次性把所有资源载入。但是,这里直接载入的资源还需要做进一步地加工才可以更为方便地使用。但是这些加工代码放哪里呢?如果再写个资源管理器来加工这些资源,那么每一次新加入一个敌机(或者其他物体),都会加入一些新的外部资源,加入后就需要在那个资源管理器里增加加工代码。这显然也不合适。所以,应该为每一个新加入的物体配置一个其自己专有的资源管理器,用来加工其自己所需要的资源。(对于敌机这类精灵物体,通常都是加工一些帧图片)

       类似于其他物体都可以这样做。(是一个新的尝试)

 

       其三,

       碰撞检测部分,这里依然可以使用矩形框来进行粗略的碰撞检测。这里存在四种碰撞检测:主角与敌机的检测,主角与敌机子弹的检测,主角与宝物的检测,主角子弹与敌机的检测(景物也可以当作敌机)。

       检测主角与敌机时,如果发生碰撞,游戏通常会删除主角(设置主角死亡)和敌机(内存上的删除)。这里可以把主角对象的指针传给敌机管理器检测。

       注意,这里其实可以给每一个物体设置一个状态!不同状态下其行为是不同的。

       全局应该存在一个碰撞检测单件,虽然目前为止可能它只有一个检测矩形区域是否相撞的接口。

       检测主角与敌机子弹时,如果发生碰撞,主角通常会损失一些生命值(损失完的话就死亡),然后删除子弹(内存上的删除)。这可以把主角对象给敌机子弹管理器检测。主角损失多少生命值?这由与其碰撞的敌机子弹的属性来决定。

       注意,敌机子弹和主角子弹有什么不同?不同之处只在于敌机子弹只与主角发生碰撞检测,主角子弹只与敌机发生碰撞检测。因此根本没必要在这里分为两个管理器,完全可以使用一个管理器,提供两种检测的接口以及两个容器即可

       检测主角与宝物时,如果发生碰撞,宝物管理器就根据碰撞到的宝物本身的属性来更改主角的一些属性,然后删除宝物。

       检测主角子弹与敌机时,这个就比较复杂,因为是多对多的检测。这个可以在主角子弹管理器内放置一个指针(不是语言层次的指针),用来指示当前正在判断的子弹。进行检测时,就把这个指针指向的子弹传给敌机管理器进行检测。然后改变这个指针。直到指针回到容器头部。进行检测时,主角子弹对于敌机通常的作用是减少敌机的生命值,减少多少生命值是由子弹本身的属性决定的。当敌机被击毁时,通常都会给主角以一定奖励。

 

       可以看出,很多管理器都需要主角对象的指针。于是可以在管理器初始化的时候就把指针传给它,让其maintain the pointer

      

       其四,

       如何确定每一种敌机(与之类似的也包括每一种宝物,子弹之类的)的各种初始属性?这一次我不想硬编码,我想从外部配置文件读入!这些属性包括它的攻击力,初始生命值等等之类。每一种敌机的初始属性都有一个外部配置文件来配置。每一种具体的敌机类,都有一个静态的属性读取类。这个属性读取类就负责从外部文件读入属性值然后保存下来,由与之对应的敌机类使用。注意,一定要是静态的!每次敌机在被创建时,如果发现这个静态对象未初始化,就调用其(静态对象)初始代码从外部配置文件读如属性值。如果已经初始化了,就直接使用其属性值。

       这里这个机制,其实就是拿来替代游戏里各种常量的。因为我不想把这些常量硬编码进可执行文件,而是由外部配置文件来配置。这样灵活性更大。

       配置文件除了配置各种属性外,还可以配置一些资源使用方面的信息。例如资源ID,图片上每一帧的尺寸之类的信息。这样又可以减少敌机对应的资源管理器的硬编码程度。注意,显然每一种敌机对应的资源管理器也应该是静态的。(也许这里应该叫资源加工器)

 

      

       大致整体规划信息就思考到这里。其他的架构信息可以沿用以前的方式。

 

抱歉!评论已关闭.