返回 登录
3

使用 Unity 3D 开发游戏的架构设计难点

作者:姜雪伟,网名:海阳,CSDN 博客专家,资深 3D 游戏引擎,IT 高级讲师,畅销书作者,从事 IT 行业 15 年,主导或参与了 18 款大型游戏的研发;国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。研究方向:架构设计、图形学、VR/AR 等。博客网址:http://blog.csdn.net/jxw167
声明:本文为作者投稿,版权归 CSDN 所有,未经允许,请勿转载。
责编: 屠敏,关注 VR/AR/MR 等领域,寻求报道或者投稿请发邮件tumin@csdn.net,另有「CSDN VR 开发群」,技术之路,我们共同进步,欢迎开发者加微信tm_forever_miss申请入群,务必备注姓名+公司+职位。

Unity 3D 引擎对于开发者来说,入手非常快,因为它采用的是 C# 作为开发语言,这也大大降低了开发者的门槛。但凡只要懂一门编程语言的人都能使用 Unity 3D 引擎开发,另外 Unity 3D 的内部架构设计非常好,采用的是组件开发,开发者能快速通过组件堆积出一个游戏。既然使用 Unity 3D 引擎开发游戏这么简单,那它有没有坑呢?答案是肯定的,比如开发游戏经常遇到的坑:被很多开发者吐槽的包体过大、游戏架构设计,热更新,包防破解问题等等,下面笔者分享在游戏开发中的坑及解决方案,为大家的学习之路提供一定的参考。

包体过大问题


Unity 引擎最突出的问题是包体比较大,尤其现在随着硬件的提升,游戏品质要求越来越高,游戏品质的提升主要是从两方面体现的:一是通过图片的精细和模型的面数,二是利用 GPU 提升模型材质的渲染。模型面数和材质图片会增加包体的容量,尤其对于大型游戏来说,一个包体至少 100M 以上,这对于用户来说很难接受。程序开发者使用了很多招数都无法减少包体大小,笔者也遇到类似问题,通常的做法是将大部分资源放到资源服务器上,程序启动时,将其下载到手机本地,这么做是解决了包体过大问题,但是前期的资源下载也会影响到用户体验。

现在问题聚焦在解决资源下载问题,笔者使用了另一种解决方案:利用多线程断点续传解决资源下载问题,程序要事先打包一到两个关卡在包体中,保证玩家在断网的情况下或者是刚启动游戏时能够顺利的进入游戏。玩家在玩第一关卡的时间策划要计算好,这样可以保证在有 WiFi 网络的情况下,启动多线程在后台下载,可以同时启动两到三个线程,在玩家把关卡打完后其他关卡也会陆续保存在本地,这样可以保证游戏不会中断。当然如果出现断网的情况可以弹出提示让玩家打开 WiFi。再介绍一下断点续传功能,在下载资源的过程中防止网络中断导致下载的资源废掉,一旦网络检测不到,它会保存并记录已下载的资源字节位置,如果再检测到网络,线程自动继续下载,这跟我们使用的迅雷下载很类似。资源的下载是在用户不知情的情况下进行的,这样就不会妨碍用户体验,下面把多线程断点下载的流程图给开发者展示如下:

实现思路是:客户端启动,首先判断是否有 WiFi,因为是网络游戏 WiFi 一般是打开的。如果检测到 WiFi,首先读取本地的版本文件,然后通过 WWW 读取服务器端的版本文件,二者会有一个对比,把需要下载的资源名字存放在下载队列中,需要下载的资源分两种:一种是替换旧的资源,做法是首先删除本地旧的,再下载新的,还有一种是本地没有的,需要从资源服务器上直接下载的。下载时会在后台启动多个线程,同时下载一个到两个资源,如果网络通畅很快会下载完,如果用户把资源自己清空了,那只能重新下载。

多线程下载方案解决了包体大小问题,当然考虑到 WiFi 的带宽,对场景资源要求大小控制在 10M 左右,如果超过 10M 可以对其进行分包处理。另外需要注意的是对游戏图片的压缩,在这里推荐工具是:PhotoZoomPortable.exe。再推荐在线的图片压缩网址:https://www.tinypng.com/,二者都可以对图片进行压缩,另外对于图集的使用,推荐图集工具:Texturepacker,相比 UI 自身的图集,Texturepacker 打出的图集更节省空间。

架构设计问题


关于架构设计,很多人对此褒贬不一,笔者认为架构设计还是非常重要的。Unity 提供了各种开发组件,导致很多开发者遇到问题不是想着如何解决而是先在网上搜索看看有没有别人实现的组件,这种做法不能说是错误的,至少你在使用别人组件时是否能够完全掌握它,能否看明白人家写的东西,开发游戏不难,难在游戏后期的版本更新维护。记得我朋友公司做了一个游戏项目,即将上线运营,但是遇到了各类问题,其中最严重的问题是版本迭代时,各个模块功能耦合性太紧,很难进行功能扩展,牵一发而动全身,导致项目迟迟上不了线。他特意邀请我过去帮他解决这个问题,我去他公司看了一下他们的项目程序,各个模块之间逻辑互相交叉,耦合性特别强,在某个模块增加一个功能会涉及到其他模块的修改,一不留神就出 Bug,程序每天为这样的事情闹的焦头烂额,疲于应付。我根据他们的项目分析了一下出现的问题,首先是它们在 UI 这块逻辑太乱,UI 上挂接了各种逻辑脚本,我们首先拿 UI 这块开刀,去掉挂接在 UI 上的各种脚本,换句话说,UI 不挂任何逻辑脚本。我选择的架构模式是 MVC,它是架构 UI 的不二选择,将 UI 的逻辑放到了对应的各个 View 脚本中,每个 UI 面板都有自己的 View 类,Controller 主要实现的是控制 View 的切换显示,每个 View 对应自己的 Controller 模块,Model 模块处理的是 UI 面板上的数据更新。

思路理清了后,接下来就是整理逻辑代码,花了整整两个星期加班加点把这块逻辑重新写了一遍。接下来是理顺项目中各个系统的设计,这块主要体现在技能系统上,它是游戏核心与玩法直接有关系的。关于技能系统的设计方式也是很多的,以前我做的是把动作和技能系统放在一起,使用的是 FSM 有限状态机,这样设计也是可行的。关于我朋友公司的这个项目改造,由于它前期已经写好了,只是耦合性太高,只能在它原有的基础上进行修改,各个模块之间互相交叉,我对它们的改造采用的是模块化设计,用于降低耦合性,架构图如下所示:

图中显示的各个技能系统是需要自己封装的,Router 是所有技能对外的逻辑接口,它是联系各个技能系统与对应角色逻辑的纽带。不论是 NPC 和玩家角色,它们都需要调用 Router 函数中的接口去实现技能逻辑。Router 与 NPC 和玩家之间的关联,我采用的是消息传送的方式,就是说如果需要用到 Router 中的函数可以通过消息发送的方式进行,这样减少了模块之间的耦合性。一旦有需求变化只需要维护好 Router 类即可。在这里友情的给读者提示一下注意事项,在重构代码时,不要把整个项目重构,那样很容易破坏项目的整体性而且容易造成功能细节丢失,导致经过重构后的项目被废弃。如果出现这样的结果,还不如不重构。一般重构代码时,先把需要重构的模块熟悉了才动手做,而且重构时以模块为单位去重构代码,采取各个击破的方式,重构后的游戏项目在扩展性方面明显改善。所以说游戏架构对于产品来说是非常重要的,游戏产品上线只是第一步,后期版本迭代才考验你产品架构设计的好坏。在这里不是给读者介绍如何架构好,而是做适合于你游戏产品本身的架构设计。

游戏热更新


游戏产品的热更新开发,网络上有很多人写过关于 Unity 的热更新的使用案例,笔者由于项目需求也使用热更新开发过游戏,在这里谈一下我的使用心得。我选择的实现方案是用 ulua 实现的热更新,使用热更新的主要目的是后期版本更新逻辑时用户无需重新安装程序包,把编写的逻辑和资源一起放在资源服务器上,可供程序启动下载。在这里推荐使用网上的 SimpleFrameWork 框架,网上有使用介绍说明,在这里就不啰嗦了,大家看一下 SimpleFramework 工程文档就明白了,使用 uLua 编写逻辑时,考虑到性能问题,一般都是用在 UI 上面,因为游戏上线运营后,各种活动的设计实现都是在 UI 层,如果核心玩法改变这个还是建议包体整体更新。每个 UI 逻辑都是使用 ulua 实现的,使用 ulua 的设计框架如下图所示:

实现思路:客户端启动时,首先通过 Http 协议从服务器下载版本文件与本地的版本文件进行版本比较,把需要下载的资源加入到链表中。然后再通过 Http 协议去服务器请求资源下载,将资源从资源服务器下载存到手机本地供客户端加载使用。在 UI 加载时由于 ulua 自身的问题,程序直接加载 UI 资源比较缓慢,在这里我是用的预加载方式就是资源更新完成后,将 UI 资源大部分预加载到内存中并将其设置为不可见,在 UI 切换时直接设置为可见即可,明显提升了效率。还有一个问题是 ulua 的内存释放要及时,防止占用内存过多影响效率。

包体的防破解案例


包体被破解一直是困扰程序员的难题,由于现在破解技术的快速发展使得我们对产品的保护显的尤其重要。下面介绍一下防破解的技术:

最常用的技术是对代码进行混淆,但是这个只是防治那些想破解代码的人,这样的防破解方式只防技术,现在很多上线的包被破解并不是采用这种方式实现的,盗版项目通常是将正版项目进行破解、篡改后重新打包生成的应用,也就是通常说的二次打包。如果移动端项目能够具备防反编译、防反破解能力,就可以有效的防止游戏项目被盗版。接下来介绍一下我的做法,架构如下图所示:

实现思路:首先对客户端的代码进行混淆,避免代码的破解,再就是加了验证消息数据合法性,如果有玩家利用破解工具绕过付费,直接购买道具,这块交给服务器去处理,服务器会对你付费和不付费的数据做一个验证,如果数据合法会存入数据库,否则把数据丢弃掉,同时把账号封掉,加入数据库黑名单永不准登陆,目前这种方式可以满足需求。另外针对客户端的防破解,也给读者介绍一个比较靠谱的工具。

在此推荐给大家的是 360 加固包,360 加固保专为开发者的应用提供免费安全加固服务,独创了多重防护方式,对应用程序深度加密处理;独有的程序文字信息加密功能,能有效防止应用被反编译和恶意篡改,保护应用不被二次打包,保护数据信息不会被黑客窃取。开发者无需任何开发成本,一键上传,即可在 5 分钟内完成应用加固,从而彻底防止应用在上线后被反编译、调试、破解、二次打包和内存截取等多种威胁。

在使用 360 加固包时注意一个问题,就是在提交审核时,一旦加固包体,它里面的内容是无法被改变的,所以在使用时如果计费文件不是最新的,不要对其进行加固否则计费这块会出问题,因为经过加固的包是无法替换计费文件的,这也是笔者在使用 360 加固包时遇到的问题。

总结


使用 Unity 3D 引擎开发,虽然其上手容易,但是它的坑也很多,在此只是给读者列觉了几个重点问题,一些小问题并没有给读者介绍。作为程序员必须具备解决实际问题的能力,这就需要在实战中不断的磨砺自己,提升自己。


了解最新移动开发、VR/AR 干货技术分享,请关注 mobilehub 微信公众号(ID: mobilehub)。

评论