在本周的项目实训中,我的主要工作是完善对玩家角色的控制脚本,以及初步实现游戏中的AI功能。该AI功能包括游戏玩家角色的AI功能和游戏非玩家角色的AI功能。
在玩家角色的控制方面,我们增加了新的需求,要求我们的角色,鲲,不仅能在海底自由移动,还要能飞到天上。角色的控制功能如下:
1.当角色在海底中,可以自由地在海底空间移动;
2.当角色在天空中时,只能在“水平空间”上移动。
3.角色可以从海底飞向天空,飞出海面的瞬间,角色保留垂直方向上的速度,进入天空后受重力作用,一段时间后又回到海中。
4.角色飞向天空有冷却时间,在冷却时间中,在海中的角色被限制不能进入天空中。
AI方面,由于我们小组打算实现的是一个以吞食系统为主要玩法的游戏,所以大致上的AI功能是这样的:
对于玩家角色AI,给它设定一个视野范围:
1.如果视野范围内有玩家角色(玩家或AI控制),把最近的角色设为“目标”:
(1)如果自身比目标更大或相等大小,则追赶目标;
(2)否则,远离目标。
2.如果视野范围内没有玩家角色,但是有食物(在海中的一些小鱼小虾等,静止或非玩家AI控制),则朝食物的方向移动;
3.如果视野范围内没有其他玩家或食物,则按一定规则随机移动。
对于非玩家角色AI(食物)相对简单,同样设置一个视野范围:
1.如果视野范围内有玩家角色,则远离最近的角色;
2.否则,按一定规则随机移动。
仔细分析这些功能需求就可以发现,这些功能之间有很多相似甚至重复之处,尤其是在玩家AI与食物的AI之间,同时还有一些地方,可以复用之前实现的玩家控制的脚本,因此在此处如果能有一个良好的类架构和类关系的设计,应该就可以减少大量的代码重复,但是在此处代码的可重用之处又显得有些混乱,因此在此处的类的设计还需要好好动一下脑筋。此处恰好也是我在本周实训中觉得感悟最深收获最大的地方。
按照我最初的设想,为了实现上述的所有游戏功能,应该设计的类有5个,这5个类的按照层级可以分为两个部分:
第一部分是底层的Behaviour类型,实现角色的一些行为,包括玩家角色与食物的移动、转向,以及玩家角色特有的在天空中的一些行为,等等,这个部分包括两个类:与“通用”的行为相关的ObjectBehaviour类和主要实现游戏角色行为的PlayerBehaviour类(“食物”的行为直接使用ObjectBehaviour);
第二部分是上层的控制器与AI类型,通过玩家的输入或者AI,操控游戏角色在游戏场景中执行各种操作,例如控制器的功能包括不同输入的处理函数,AI的功能包括追逐玩家、逃跑、随机漫游等等,这些操作将使用底层Behaviour类型的行为。这部分包括三个类:玩家控制器PlayerController类、玩家AI PlayerAI类和食物AI FoodAI类。
因此,FoodAI需要使用ObjectBehaviour、PlayerAI与PlayerController类需要使用PlayerBehaviour,再分析游戏功能需求,发现PlayerBehaviour的功能是ObjectBehaviour功能的延申,因此PlayerBehaviour类作为ObjectBehaviour类的派生类,同样PlayerAI类也应派生于FoodAI类,那么这些类的关系图应该看起来如下:
看起来这样子的设计挺合理,类的关系也比较清晰,但实际上却遇到了“菱形继承”的问题。虽然允许使用多继承,但一般来说隐患很多,项目开发时不会使用,因此该设计需要修改:一开始的想法是去掉PlayerAI与FoodAI的派生关系,初衷是维持类结构之间的清晰合理,但是由于PlayerAI可复用FoodAI的代码很多,所以否决了这个方案;第二个方案是给PlayerAI与FoodAI建立依赖关系(降低类的耦合),在PlayerAI中建立一个FoodAI的引用并调用它的功能,不过感觉仍然没有解决菱形继承,而且FoodAI的功能往往也需要使用它自己的数据,所以也否决了这个方案;再然后是去除PlayerBehaviour与ObjectBehaviour的派生关系,但是PlayerBehaviour毕竟也需要实现ObjectBehaviour的功能,代码重复似乎不可避免......
经过一番思索之后,本人最终敲定的类设计图如下:
这里对PlayerBehaviour类的含义作出了改变,它不再包括那些“通用”的角色行为,这些行为只被放入ObjectBehaviour类之中。在该设计下,没有可以“全部包办”游戏玩家角色所有行为的类型,玩家角色的行为交由PlayerBehaviour类与ObjectBehaviour类共同完成,同时ObjectBehaviour类的行为又可以被游戏食物AI使用。如此的设计算是最大限度的提升了代码的复用,但是类之间的关系不免显得有些混乱,另外当游戏的角色类型、角色行为变得更加丰富的时候,对角色的行为类的设计会变得非常麻烦。
在此,对游戏功能的类关系图的设计就告一段落了。虽然可能还有更好的设计方案,不过没有关系,至少在这个类关系图的设计中,尤其是在思考的过程中,感觉自己的收获还是非常大的,算是一次不错的锻炼。目前已经进入了代码实现阶段,当前正在进行功能调试......
游戏开发实训中的一些其他杂记:
1.在Unity中导入角色动画的问题:我们的项目组使用Maya作为建模软件和角色动画软件,因此需要处理Maya模型动画导入Unity的问题。Maya模型动画导出时需先进行烘焙模拟,然后导出为FBX文件,Unity再导入这个文件即可使用:
(1).Maya制作模型和动画;
(2).Maya编辑->关键帧->烘焙模拟;
(3).Maya选择全部模型,文件->导出当前选择->选择FBX作为导出格式导出;
(4).Unity->Assets->Import New Asset->选择上一步导出的文件导入;
(5).在Unity使用模型时,把导入的模型拖到场景,把该模型的游戏对象作为游戏角色的子节点;
(6).给模型对象添加Animator组件,把导入模型中带有的动画加入到组件中并设置为初始的动画。
2.C#Script的重命名问题:如果一个脚本并未被其他脚本引用,那么只需要直接修改文件名同时修改其对应的类的类名即可,如果有引用该脚本的地方,则需要检查这些地方是否需要跟着修改。最好的做法是避免脚本的重命名。
3.即使是一个小型项目的开发,架构啊设计这些还是要认真做的,肯定不能上来就编码,否则可能会有无穷无尽的隐患。(目前隐约觉得我们项目组貌似跳进了这个坑里面)