首页 > PHP资讯 > Python培训 > 制作跨平台3D军事动作游戏所面临的挑战

制作跨平台3D军事动作游戏所面临的挑战

Python培训
  所谓3D军事动作游戏并非只是简单的拥有回合式动作系统的卡牌,而是能够实时模拟、同步的3D动作游戏。在使用Unity引擎开发3D动作游戏的过程中,通常会遇到如何组织和实现所有关卡、优化性能等问题,在此,我想分享一下我们团队在《血战长空》开发过程中探索出的经验之法。

  如何在Unity中组织并建立所有关卡?

  找同类型游戏做参考

  首先,如何在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?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的变换信息。我们采取的做法是:

  第一步:运行时移除掉不需要的GameObject子项,需要时再装回来。

  第二步:降低葡萄根的调用频率,同时一帧之内不对transform.position赋两次值。但Unity并没有提供一个同时修改position和rotation的方法,导致动鱼目前一帧内仍然至少更新两次葡萄。

  更进一步:LOD。很多经典的3A游戏都采用了这个技术,降低视野外和距离远的单位位移更新频率,以此来获得高效率的渲染运算。

本文由欣才IT学院整理发布,未经许可,禁止转载。