所谓3D军事动作游戏并非只是简单的拥有回合式动作系统的卡牌,而是能够实时模拟、同步的3D动作游戏。在使用Unity引擎开发3D动作游戏的过程中,通常会遇到如何组织和实现所有关卡、优化性能等问题,在此,我想分享一下我们团队在《血战长空》开发过程中探索出的经验之法。
首先,如何在Unity中组织和建立关卡?第一件事就是找同类型游戏做参考,将它们的共性提炼出来,以此来避免浪费精力做出一些似是而非的东西。尤其对于小团队来说,有效的学习和模仿可以少走许多弯路。在开发《血战长空》游戏时,我们参考了IL2、War Thunder和Armed Assault等诸多飞行射击类游戏。
它们的关卡编辑器都有一些共性,比如Unit Spawner(单位生成和初始设定)决定生成的是什么,即对应游戏过程中的哪个部分,开发者可以用它写一个下达框;Unit Waypoint(单位之后的去向和动作)是在过程中干什么,选择作战还是不开火?一定要作战怎么撤退?最后一个是Trigger(条件和触发),定一个条件,用于脚本交互。
即使是编写三维场景,也需要契合逻辑。拿Trigger来讲,一种是单位的Trigger,还有一种比较特殊的是炸弹Trigger,炸弹掉落到这一区域,会让单位掉血,开发者需要确保在有限的时间内它不会被炸毁。这些设计方式通过组件非常容易实现,开发者可以直接把一个关卡存储成Prefab。
在设计好初始单位、下一步动作路线以及触发条件反应后,又该如何定义一些比较特殊的关卡?来指引玩家按照既定顺序进行。比如有三个关卡,应该是先轰炸A后打B最后再打C,而不是倒过来。每一个单机游戏的Model都有不同的解决方案,要根据团队的实际开发能力、个人习惯以及项目类型来选择。
在关卡流程设计中,该选择数据驱动还是代码驱动?这个问题既简单又复杂,如果投资人或公司老板能够懂一些这方面的知识,那么游戏开发人员或许会少点心酸。数据驱动就是常说的可视化编程,优点是解放工程师,设计师可以消化掉所有流程部门的工作,不用添加程序就可以设置关卡,这对国内手游来讲是至关重要的功能。但同时存在诸多缺点,首先,开发者自创一套系统方案需要大量成本,每新入一个关卡设计师就需要重复教学。
最关键的问题是,团队花费大量时间来实现这么一大套系统,就意味着最快展现给投资人或给团队自身反馈的时间也会变长。有时候团队两三周没拿出什么对外的feature,并不是真的没有成果,只是可能是在实现底层、优化内层、搭建基础架构,这些繁芜系统的工作,在数据驱动的前期,尤为明显。
在对比数据驱动和代码驱动优劣之后,动鱼首先采用了纯代码驱动,使用Unity中的Coroutine功能对关卡流程进行快速设计并创建。通过代码驱动简单快捷的Hack属性,开发者可以先将关卡设计出来做成Demo交给投资人,然后再用数据驱动构建。这样,即使整个后续程序都没有开发完甚至没有开始,却可以很好地展示游戏性能。
而这种先代码后数据驱动的方式,对于关卡设计师来说,最High的事莫过于他们不用再求着程序员了,而程序员也不用特别费劲地折腾其他工程师。尽管结构是关卡里最重要的东西,但程序员一般不关心结构,这个权利要交给关卡设计师。
确定驱动以后需要考虑的就是用uScript还是playMaker?uScript非常强大,类似于预代码生成器,支持预编一层代码,这样的好处就是速度非常快,但其预编译功能,既是优势也是劣势,每加一个关卡,就需要更新客户端。而playMaker则可以看做是一个状态机管理器,基本上想到的状态机功能都有,但最大的缺点是传值非常难,我们的解决方法是在action上留可编辑的variable,拖拽需要考虑的参数。
图1 可视化阶段流程
如果用来做线性游戏的话,则尽量一个state放一个action,在策划看来就非常可视化,每一个阶段都清晰地表明了动作,哪怕是瞬时的,如图1所示。多数关卡可以单纯通过已有的action组织出来,特殊的关卡可以专门写脚本,使用特殊的state和action。
“过早的优化是万恶之源”——这句话几乎所有的程序员都耳熟能详。在早期,优化并没有什么实际意义,很多人在用某些引擎时第一件事就是自己封装一套STR,却没有思量STR外壳、内部好不好使。验证优化的唯一标准就是去测试它,而不是凭感觉在一开始就否定它。我们在测试葡萄GameObject时,发现在Android 4.0系统中飞行耗时0.54ms,这显然是不能接受的。
为什么将GameObject称之为“葡萄”?GameObject下包含了Renderobj、AI、Gun等非常多的子项,每个子项下又有很多子项,由此形成了一个极为庞大的葡萄串。许多开发者习惯于此的原因就是这样的葡萄看起来清晰明了,使用方便。但同时,葡萄无形中增加的计算量也是巨大的,因为每一次修改Plane的Transform.position、localPosition、rotation、localRotation意味着要更新所有子GameObject的变换信息。我们采取的做法是:
申远 成都动鱼数码科技有限公司技术总监
本文将刊登在《程序员》5月A刊上,订阅详情可点击: http://dingyue.programmer.com.cn/
CSDN移动将持续为您优选移动开发的精华内容,共同探讨移动开发的技术热点话题,涵盖移动应用、开发工具、移动游戏及引擎、智能硬件、物联网等方方面面,如果您有想分享的技术、观点,可通过电子邮件(tangxy#csdn.net,请把#改成@)投稿。
第一时间掌握最新移动开发相关信息和技术,请关注mobilehub公众微信号(ID: mobilehub)。