极客时间已完结课程限时免费阅读

37 | 移动开发新大陆:工作三年半,移动开发转型手游开发

37 | 移动开发新大陆:工作三年半,移动开发转型手游开发-极客时间

37 | 移动开发新大陆:工作三年半,移动开发转型手游开发

讲述:冯永吉

时长17:32大小16.02M

你好,我是张绍文。15 年认识庆文的时候,他还在微信读书负责 Android 端的性能优化工作。某一天,他跟我说想转岗去尝试一下游戏开发,当时我脑海里浮现了两个想法,一个是游戏部门传说中 60 个月的年终奖,看起来游戏是一个非常有“钱途”的方向;另外一个还是担忧,抛弃掉 Android 开发多年的积累,转去完全不熟悉的游戏领域,他是否可以胜任。
两年过去了,庆文以他的个人经历亲身证明了两件事情:
第一,游戏开发并没有想象中那么困难。当年他是 Android 版微信读书的技术核心,如今在新的岗位上依然也是技术核心。“一通则百通”,技术是相通的,最珍贵的是我们的学习能力和钻研精神。
第二,客户端平台知识依然非常重要。手游虽然有非常独立的开发体系,但是它还是运行在 Android 或者 iOS 系统之上。App 开发需要用到的很多技术,游戏开发也需要用到。作为 Android 开发,我们一层一层往底层走的优化能力,反而是其他大部分游戏开发所不具备的,也是我们的优势所在。
在我看来,无论移动的未来如何发展,不管是大前端的天下,还是转向手游、IoT、AI、音视频等其他方向,今天我们所熟悉的 Android 平台知识以及学习这些知识所沉淀下来的能力和方法,都是最宝贵的财富。下面我们一起来看看庆文同学的移动开发转型手游开发的那些事。
你好,我是李庆文,来自腾讯旗下一间手游工作室,应绍文的邀请,在《Android 开发高手课》里和你聊聊手游开发那些事。
我在 2017 年 4 月,从 App 客户端开发转岗成为一名“用命创造快乐”的手游客户端开发。在转为手游开发之前,虽然玩游戏会被游戏精美的画面吸引,但是并不清楚游戏是如何将这些精细的画面呈现出来,觉得游戏开发好像一个神秘的组织一样,不知道游戏开发团队的同学每天在做什么。如果你也对游戏开发有些好奇,不知道是不是也有我之前同样的困惑?现在我以一个亲历者的身份,跟你讲讲转向手游开发的那事儿。

揭开手游开发的面纱

一般来说,一个手游项目组包括制作人、策划组、美术组、运营组、程序组、音频组。其中游戏核心部分完全由项目组自己完成,部分美术、音频可以交给外包来完成。
策划组分为玩法策划、数值策划,是整个游戏的灵魂,一个游戏的核心玩法是否好玩、周边系统能否更好地支撑核心玩法,是整个游戏成败的关键。有些团队也会把运营组放到策划组当中,运营同学主要的工作职责是外部合作、策划游戏内的活动、根据活动数据对游戏玩法或者活动进行相应调整,希望可以尽量延长游戏生命周期并提高游戏收入。
美术组包括原画师、视觉设计、2D/3D 视觉特效设计,其中负责视觉特效的同学与负责程序的同学沟通较多,主要是因为程序需要与动画配合,比如某个动画播放到某一个关键帧之后,程序要处理某个特定逻辑。
App 开发的程序组同学关注的更多是手机系统的架构,希望尽量多了解系统能为 App 提供的接口或者能力。而手游的程序组同学更多是关注游戏引擎的架构和如何在引擎的基础上优化游戏性能。
下面我以 Cocos 引擎为例,带你看看手游的开发流程以及手游是如何运行的。
1. 游戏架构
以我的游戏项目为例,游戏整体架构如下图所示。
其中:
资源更新模块让游戏能够不断发布 Bugfix 和 Features。
配置系统提供给策划和运营同学,主要是编辑 XLS 文件用于配置游戏内的关卡、活动等。策划同学的配置会在游戏编译过程中自动转表,根据配置文件生成 Lua 文件。
Services 管理着游戏内的全部数据。
网络模块负责与后台建立 Socket 并通信。
游戏内使用 MVC 模型控制各个游戏内模块的跳转。
在单个功能模块中,逻辑与动画分离,逻辑层产生动画事件,动画层消费动画事件并让游戏内的精灵根据事件执行特定动作。
2. 游戏场景设计
Cocos 采用节点树形结构来管理游戏对象,一个游戏可以划分为不同的场景(Scene),一个场景又可以分为不同的层(Layer),一个层又可以拥有任意个精灵(Sprite)。游戏里关卡、周边系统的切换也就是一个一个场景的切换,就像在电影中变换舞台和场地一样,由导演(Director)负责不同游戏场景之间的切换。一个 Cocos 游戏的基本结构如下:
在同一个场景中的多个精灵可以通过执行动作(Action)来实现缩放、移动、旋转,从而达到让游戏“动起来”的目的。
Cocos 引擎中,坐标系 X 轴向右、Y 轴向上,Z 轴(Z-Order)垂直于手机屏幕指向屏幕外,由于是 2D 游戏,所以 Z 轴只用作控制游戏元素的前后顺序。同一个场景中两个重叠或者部分重叠的 Sprite,Z-Order 大的精灵会遮挡住 Z-Order 小的精灵,相同 Z-Order 的精灵,后添加到场景中的会遮挡住先添加的。
有了树形结构和 Z-Order,就能利用 Cocos 引擎构建出任意 2D 游戏场景了。
3. 手游的运行流程
游戏的主 Activity 在onCreate时候创建一个 GLSurfaceView,它继承自 View,是引擎用于绘制游戏内容的。同时 GLSurfaceView 也接受玩家的点击事件,用于引擎与玩家的交互。
GLSurfaceView 创建之后,引擎开始执行main.lua脚本,导演调用runWithScene接口,游戏就进入到第一个“场景”中了。GLSurfaceView 中维护了一个while循环,循环中发生的事件(比如 SurfaceView 创建、宽高发生变化等)通过Renderer接口传递给外部。Renderer其中一个接口就是onDrawFrame,Cocos 会在onDrawFrame接口实现中根据游戏设置的帧率,每间隔一段事件通知一次导演执行一帧游戏循环。
借用《我所理解的 Cocos2d-x》书中的单帧处理流程图片,你可以看到在每帧中:
先响应用户输入,因为用户输入可能影响到当前帧接下来的游戏逻辑。
根据每个精灵设置的动画,计算精灵的位置、缩放等属性。
执行游戏逻辑,比如更新玩家得分、修改当前游戏状态等。在这里开发者依然可以更改精灵的各种属性。
遍历 UI 树,根据之前对精灵属性的设置,生成绘制命令,交给 OpenGL 绘制,最后把渲染的内容显示到屏幕上。

游戏与 App 开发的异同

1. 关于热更新
热更新是 App 开发和游戏开发都避不开的话题,但是 App 的热更新与游戏的热更新有着本质的区别。App 开发的热更新涉及整个系统层面的实现细节,比如我在老东家工作期间实现的热更新框架,需要了解的内容非常多,包括 Dex 文件的加载过程、SO 文件查找过程和 APK 编译过程的详细细节,每个不小心都可能导致热更新不生效甚至导致严重的外网 Bug。
然而使用脚本的游戏引擎是天生支持热更新的。手游热更新,也叫作资源更新,更新内容包括代码、纹理图片、界面等。
以 Cocos 引擎为例,Cocos 引擎的核心是 C++ 实现的,对外提供了 JS、Lua 接口。业务开发过程中绝大部分代码是 Lua 代码,只有涉及系统相关接口,比如支付、音频播放、WebView 等,才需要写一部分系统相关的代码。Lua 代码经过编译之后生成的二进制代码是“.luac”文件,并通过 luaL_loadbuffer 接口来加载一段“.luac”的文件内容。Cocos 引擎在初始化过程中会设置“代码查找路径”,加载 Lua 代码的时候会挨个遍历每一个被设置进来的路径,直到找到或者找不到对应的“.luac”文件。而热更新只需要下载“.luac”文件,放到优先的查找路径中,游戏重启之后引擎就会优先加载新的代码啦。
当然还有另外一种更为激进的方式,不需要重启游戏就能达到热更新的目的。
Cocos 以 LuaEngine 为入口,执行 Lua 代码驱动 C++ 部分的图形库、音频库、物理引擎等。LuaEngine 缓存了通过luaL_loadbuffer接口加载起来的代码,只要重启整个 LuaEngine 清理掉缓存的代码,就能在后续需要执行代码的时候去重新加载代码文件。这样就能做到不重启游戏也能达到真正“热”更新的目的。
其实 Unity 引擎也是类似,可以使用 xLua 等类似的技术,让 Unity 引擎也能开心地写 Lua 脚本。
对于热更新图片,只需要清理掉引擎缓存的图片缓存即可。这样引擎在下次使用该图片渲染界面是,发现在缓存中查找不到该图片,自然就会去加载新的图片了。
2. 游戏也需要优化安装包大小
在 App 开发过程中,优化安装包的大小是一个不可避免的话题。压缩图片、代码,插件动态下载等众多实现方案也都为大家所熟知。手游安装包大小可能并不像 App 安装包要求那么严格,热门游戏比如《绝地求生》《王者荣耀》,安装包大小几乎都接近 2GB。虽然玩家对游戏安装包大小不是特别在意,但有意识的减小安装包大小也是很有必要的,毕竟安装包大小会影响游戏转化率,进而影响游戏收入。
手游安装包中,图片资源占了安装包体积的绝大部分,以 PNG 图片为主。通常直接压缩 PNG 图片是有损压缩,经过游戏引擎渲染,游戏界面会出现很多噪点。这里有一种分离 Alpha 通道的压缩方案,可以供你参考。32 位透明 PNG 图片包含了四个通道:RGBA,其中每个通道占 8 Bit。把 RGBA 四个通道中的 Alpha 通道数据拆分出来存储为一张 PNG8 图片,剩下的 RGB 数据存储为一张 JPG 格式图片。JPG 格式的图片在保证高压缩率的同时也能保证图片质量,以此达到压缩图片大小的目的。这种方案的压缩率大概在 70% 左右。
在游戏运行过程中,使用纹理之前先把 JPG 和 PNG8 文件都读取到内存,将他们包含的 RGB 和 Alpha 数据重新合并后,交给 OpenGL 用于渲染。这个压缩方案简单易操作,并且运行时不需要额外的第三方库支持。
3. 游戏的性能优化
性能是开发者永远离不开的话题。手游和 App 开发一样,也需要关注游戏的各方面性能指标,比如内存、帧率等。
内存
纹理压缩,减少纹理占用的内存。我前面提到的安装优化包大小中压缩图片,也有助于减少内存占用。在美术同学能接受的前提下,降低图片深度也是快速优化内存的一个方法。
使用精灵池,尽量复用已经创建的精灵,减少屏幕中精灵创建的个数,及时回收不用的内存。
切换场景时尽快释放上一个场景的无用纹理。
帧率
减少 Draw Call。游戏引擎每次准备数据并发送给 GPU 去渲染的过程,称为一次 Draw Call。Cocos 把使用相同贴图、blendFunc、Shader 的精灵合并到同一个渲染命令中提交给 GPU。我们常说的合图就是把很多小图片合并到一张大图片中,这样当屏幕中有多个连续渲染的精灵用到同一个大图,CPU 就会(有可能)把它们合并之后统一提交给 GPU。另外 Cocos 合并渲染命令是根据精灵在场景中的顺序来做的,最终的合并效果不一定是最优的。我们可以实现自己更优化的合并逻辑。
减少屏幕内需要渲染的精灵个数。如果屏幕中有“成组”的元素需要绘制,比如排行榜中每个玩家的 Item,在 Cocos 中可以使用 CCRenderTexture,把每个“成组”的元素绘制到 CCRenderTexture 绑定的纹理,然后用 CCRenderTexture 替代原有的 Item。这与 Android 开发中自己实现 View 的 onDraw 函数类似,并且这也是减少 Draw Call 的一种方式。
分帧。真的遇到 CPU 密集型的任务时,例如同屏幕确实需要大量精灵,可以把它们拆分在不同帧里,尽量保证游戏内每一帧在规定时间内完成,否则会出现卡帧现象。

App 开发转手游开发的思考

刚刚过去的 2018 年是游戏比较惨淡的一年,游戏版号从暂停审批到现在终于慢慢开始放出,简直是千军万马过独木桥。但从目前来看,2018 年确实也像某些大咖说的那样,可能是游戏行业未来几年最好的一年。国内拿不到版号的游戏只能考虑出海来寻求出路,但是出海需要在海外当地运营或者找海外代理。自己运营可能会遇到水土不服,画风或者游戏内容也可能不满足当地玩家的需求;找海外代理,却可能面临连游戏代码都被代理商卖掉的风险。
手游早已经结束了野蛮生长的年代,6 年前可能随便一款游戏都可能成为爆款,类似捕鱼达人、保卫萝卜,它们诞生在 Android、iOS 手机爆发的那几年。而现在的游戏玩家需要的是更新颖的玩法和更加精细的游戏体验。例如 MOBA 类的《王者荣耀》、SLG 类的《乱世王者》,甚至细分领域的《恋与制作人》,也都在各自的玩法上不断打磨,让玩家心甘情愿“氪金”。如果想要转向这个赢者通吃的行业,确实需要谨慎,提前考察好目标团队是否符合你的职业发展、是否有盈利能力,尽量避免踩坑。
1. App 开发转手游开发,可行吗?
2018 年和 2019 年,市场对 App 开发的岗位需求量已经不像几年前那么大,而且也有一些同学也咨询过我 App 开发转手游开发是否合适。关于这个问题,我的回答是:可以转到手游开发岗位,而且难度并没有想象中那么大。
手游开发跟 App 开发相比,只不过是换了工作内容,关注的领域不同而已,基本原理是相通的。App 开发需要用到的很多技术,游戏开发依然也需要用到,比如卡顿分析、网络、I/O 优化。而且游戏的大部分核心逻辑库是与平台无关的,所以不必担心适应不了新的工作内容。下面我来总结一下转到手游开发的优势和劣势。
优势
对手机系统有深入了解,能迅速切入一部分游戏团队内的工作内容。比如我刚刚转到手游团队时解决的第一个问题:游戏在 Android 系统上 JNI 找不到函数的 Crash 稳稳占据了每个版本的前三名,版本 Crash 率由于这个问题而一直保持在 1% 左右。当时由于团队对系统没有深入了解,所以并没有很好的解决办法。这个问题其实读一遍 Android 系统查找 Native 函数的代码,基本就能找到解决方案了。
劣势
毕竟是两个不同的开发方向,转方向的同学也需要迎接压力。与毕业后直接进入游戏行业的同学相比,“半路出家”的同学相对缺乏原始技术积累,需要从基础的概念开始学起,比如上面提到的 Draw Call、合图、OpenGL、Shader,需要消耗大量精力去学习。所以需要转方向的同学足够自律,主动补齐这些技术短板。
2. 转方向后的技术路线
有些同学说 App 开发者的技术路线宽,担心手游开发者将来技术路线会越来越窄,将来不好找其他工作。有这个担心是正常的,手游开发岗位的市场需求量比移动开发需求量小太多,但这不应该成为害怕转手游开发的理由。个人觉得需要从一个更宏观的角度看待这两个不同的开发岗位,不要钻在技术的牛角尖里无法自拔。技术通道无风险,而更应该担心的是游戏的政策风险。
小游戏在 2017 年和 2018 年真是火了一把,鉴于小游戏入门简单、上手快,想要转方向的同学可以先用小游戏来练手。“麻雀虽小,五脏俱全”,看明白一个小游戏的执行流程之后,相信你对游戏开发也就会有一个感性的认识了。
最后祝各位开发者游戏愉快!
欢迎你点击“请朋友读”,把今天的内容分享给好友,邀请他一起学习。我也为认真思考、积极分享的同学准备了丰厚的“学习加油礼包”,期待与你一起切磋进步哦。
分享给需要的人,Ta购买本课程,你将得18
生成海报并分享

赞 6

提建议

上一篇
36 | 跨平台开发的现状与应用
下一篇
38 | 移动开发新大陆:Android音视频开发
unpreview
 写留言

精选留言(5)

  • Reiser
    2019-04-02
    非常感谢庆文关于转型的分享。之前我也有过转型大数据的打算,不过最终还是决定深耕Android。之所以不转型,还是因为自己的技术并不是很好,觉得自己 Android 都不能做到极致,转型也做不好。当然做好 Android 的同时,也会扩展技术面,每个热爱技术的都想成为全栈啊

    作者回复: 是的,如果有从上往下打通关的能力,我们去做其他事情也是降维打击

    9
  • Geek_212b1d
    2020-08-03
    写过4年安卓,2年后台,几个月的游戏,有计算机基础其实学起来都差不多。但是最近找工作处处碰壁,还是得看深度。
    共 1 条评论
    3
  • 七月
    2019-04-02
    转游戏开发是学Unity3d好,还是cocos2d好一点呢?

    作者回复: 个人推荐还是Unity3d吧,应用场景更广一些,而且配套设施更成熟。但是cocos2d作为入门也不错,毕竟是开源的,可以学习

    1
  • Alan K
    2019-04-02
    安卓系统有可能实现分帧绘制吗

    作者回复: 分帧绘制可以说一种思想,并不是技术,理论上安卓系统也是可以实现的

    2
  • 2019-04-02
    都是写代码,只是业务场景不一样
    共 1 条评论