使用 Unity 开发游戏入门

本指南将简要介绍典型的游戏开发周期。阅读本指南后,您可能会发现将其用作参考也很有用。

使用 Unity 开发游戏时,开发生命周期由三个阶段组成:

  • 规划和设计
  • 开发和测试
  • 发布和维护

规划和设计

在规划和设计阶段,您需要确定如何制作游戏。您要决定如何应对面向移动设备开发游戏的挑战,并确定在开发中使用的工具和流程。

向所有团队成员征求意见

与美术、工程、设计、音频和制作团队合作,一起确定并记录实现任务。例如:

  • 美术团队可以为角色和环境制作资源纹理和网格预算。
  • 工程团队可以确定针对每个平台进行内存和性能分析的检查点。
  • 设计团队可以规划能够实现所需体验的游戏机制。
  • 音频专家可以审核对界面、2D 和 3D 空间音效之间的声音连续性的要求。
  • 制作团队可以沟通发布要求,帮助团队协调一致且有条不紊地开展工作。

面向移动设备设计游戏

面向移动平台开发应用需要考虑一些特定因素,例如:

  • 可变的屏幕宽高比
  • 功耗
  • 散热和处理器降频
  • 触控输入
  • 跨平台开发
  • 图形 API(Vulkan 或 OpenGL ES)

如需详细了解面向移动设备设计游戏时特有的考虑因素,请参阅 Unity 网站中有关使用 Unity 进行面向 Android 的开发的文档和 Google Play 学院门户。

开发和测试

在开发和测试阶段,您需要制作游戏并进行测试和发布前准备。您要在 Google Play 上进行一些有限内部测试,为满足发布要求做好准备。您还要基于 Play Asset Delivery 和 Unity Addressables 系统在 Unity 中优化部署策略并整理资源。

以下各部分将介绍旨在帮助您面向 Android 开发游戏的一些 Unity 工具和技巧。

渲染

渲染是将 Unity 场景中的 3D 和 2D 资源绘制到屏幕上的过程。虽然 Unity 引擎会负责处理渲染,但您也必须针对 Android 平台考虑几个因素。

纹理

根据目标设备,确定是否需要使用最大的纹理尺寸。在分析内存分配时,请查看更改目标纹理尺寸有可能节省多少内存。

帧时间

为了防止 Android 设备过热,应以平均帧时间值低于 21 毫秒为目标。在某些情况下,例如在加载期间或播放短片时,帧时间可以超过 21 毫秒,但核心游戏体验的帧时间阈值仍应保持在 21 毫秒以下。

在移动平台上,如果没有达到最低目标,强制 VSync 会对帧速率加以限制。例如,当屏幕刷新率为 60Hz 时,如果帧速率没有达到 60fps,那么游戏的帧速率就会被限制为 30fps;如果帧速率没有达到 30fps,则会被限制为 15fps。

许多 Android 设备的屏幕刷新率为 60Hz 和 120Hz。请权衡利弊:如果将帧时间的目标定得更低(刷新率为 60Hz 时以 10 毫秒为目标,刷新率为 120Hz 时以 5 毫秒为目标),就可以避免渲染速率较高所带来的温控降频和耗电过多风险。

如需在 Unity 中为游戏设置一个特定的帧速率,请使用 Application.targetFrameRate

当应用呈现下一帧所需的时间比屏幕刷新率要求的时间长时,可以借助 Android Frame Pacing 库实现流畅的渲染。

如需启用该库,请在 Project Settings > Player 中,勾选 Settings for Android 下的 Optimized Frame Pacing 复选框。

对话框中显示了“Project Settings > Player Settings > Optimized Fame Pacing”
图 1. 在 Unity 2019.2 及更高版本中,Optimized Frame Pacing 位于 Player Settings 下。

Vulkan API

Vulkan 是一个跨平台的高性能 3D 图形 API,与 OpenGL ES 相比,它的开销更低。Unity 可以通过两种不同的方式来使用 Vulkan。

Auto Graphics API

您可以通过“Auto Graphics API”选项来使用 Vulkan,但这种方式可能会导致不同的行为,具体视您安装的 Unity 版本而定。如需选择此选项,请前往 Project Settings > Player > Rendering

在选择要使用的 Unity 版本时,请注意以下事项:

  • Unity 2021.1 及更低版本不支持通过“Auto Graphics API”选项来使用 Vulkan。Unity 会尝试使用 OpenGL ES 3.2。如果设备不支持 OpenGL ES 3.2,Unity 会回退到 OpenGL ES 3.1、3.0 或 2.0,按顺序依次尝试。
  • Unity 2021.2 及更高版本会优先使用 Vulkan。如果设备不支持 Vulkan,Unity 会回退到 OpenGL ES 3.2、3.1、3.0 或 2.0。
Project Settings > Player Settings > Rendering > Auto Graphics API
图 2. 设置 Auto Graphics API。

手动设置图形 API

或者,您也可以通过禁用“Auto Graphics API”来手动启用 Vulkan。如果您使用的是 Unity 2021.1 或更低版本,这是使用 Vulkan 的唯一方式。

如果 Vulkan 在此列表中的排序高于 OpenGL ES,Unity 会优先尝试使用 Vulkan。如果设备不支持 Vulkan,Unity 会使用 OpenGL ES 运行。如需详细了解 Android 版 Vulkan,例如如何使用新式图形 API 并优化游戏性能,请参阅 Vulkan 使用入门

Project Settings > Player Settings > Rendering > 图形 API
图 3. 在禁用“Auto Graphics API”选项的情况下手动设置图形 API。Vulkan 是第一个选项。Unity 回退到 OpenGL ES 3.0。

绘制调用

屏幕上显示的所有内容都与一个或多个绘制调用相关联。在移动平台上,您应当优化发送到图形处理器 (GPU) 的绘制调用并减少此类调用的次数。

您可以将绘制调用想像成在红绿灯前排队的车辆。从红绿灯变绿后到再次变色前,允许一定数量的车辆通行。当红绿灯变成黄色时,即表示已达到理想的目标帧时间(21 毫秒),当红绿灯变成红色时,即表示已达到 33 毫秒的帧时间限值。但凡超过该限值,都会影响下一个渲染帧,导致帧速率低于您的目标,即 30fps。

如需了解如何在游戏中提高绘制调用性能,请参阅 Unity Support 网站上有关批处理的文章。

阴影

阴影投射绘制调用对 GPU 造成的负荷可能是最高的,即使是简单的环境也会消耗大部分 GPU 时间。为了降低阴影投射的开销,请尝试使用硬阴影而不要使用软阴影。如果这样做对低端设备而言 GPU 开销仍然太高,可以考虑使用模糊阴影来代替硬阴影。

纹理

对于 Android 上的 RGB 和 RGBA 纹理,建议使用的纹理压缩格式是 ASTC。在 Unity 中,您至少应该对 Android 使用 ETC2 纹理压缩选项。您可以在 Unity Build Settings 下,从 ASTC 回退至 ETC2 作为备份。

如需查看各平台支持的格式的完整列表,请参阅 Unity 文档 Manual: Recommended, default, and supported texture formats, by platform

界面和宽高比

您可以使用 Unity Device Simulator 工具直接在 Unity 编辑器中预览各种设备的屏幕分辨率、屏幕方向和宽高比。您还可以在 Game 视图和 Device Simulator 视图之间切换。

如需查看该工具的预览,请观看 Simulate your Game with Device Simulator in Unity! 教程。

图 4. 正在运行 Trivial Kart 的 Device Simulator。

您可以在 GitHub 上的 games-samples 代码库中找到 Trivial Kart 源代码。

通过从下拉菜单中选择设备选项,您可以在 Device Simulator 视图中快速验证界面画布元素的布局和正确性:

Project Settings > Player Settings > Optimized Frame Pacing
图 5. Device Simulator 支持在编辑器中更改设备,让您可以尽早发现设计问题。
Project Settings > Player Settings > Optimized Fame Pacing
图 6. 在下载 Device Simulator 软件包之前,勾选 Enable Pre-release Packages

如需了解适用于 Unity 的更多界面优化技巧,请参阅 Unity 网站中的以下教程:Optimizing Unity UI

物理

Unity 内置了 Nvidia PhysX 引擎。默认设置在移动设备上的开销可能较高,因此请注意以下事项:

  • 考虑您的目标帧速率并相应设置固定的时间步长。默认值设置为 0.02 毫秒或 50Hz。如果目标帧速率为 30fps,可将时间步长增加到 0.03 毫秒或更高。
  • 考虑简化网格碰撞器并尽量缩小图层碰撞矩阵,以确定特定图层类型的游戏对象之间的交互。

如需了解移动游戏的物理设置和优化,请参阅 Unity 网站中的 Optimize Your Mobile Games 电子书

性能分析

在应用发生严重故障之前,应用开发者往往会无视或忽视性能分析。建议您最好在流程中安排专门的分析时间并遵循以下最佳实践:

  • 找到开发过程中可以分配分析时间的关键点,而不是随机安排一个时间。
  • 保存性能分析快照,以便与 Unity Profile Analyzer 配合使用。
  • 在目标设备上对游戏进行性能分析,准确了解游戏在当前开发阶段的表现。
  • 分析游戏不同部分的性能。
  • 分析玩家的游戏方式。(不要只在游戏处于空闲状态或屏幕暂停时对游戏进行性能分析。)
  • 在游戏运行一段时间后的持续模式下进行性能分析,帮助找出在移动设备变时可能遇到的降频问题。

您可以单独使用以下性能分析工具,也可以将其结合起来使用。

  • Unity Profiler:Unity Profiler 是一款完全集成的性能分析工具,可在 Unity 编辑器中针对您的代码运行,并连接到运行开发模式 build 的独立 Android 设备。

  • Android GPU 检查器:使用 Android GPU 检查器 (AGI),您可以执行帧级调试。AGI 还可分析系统服务,包括 GPU、CPU、内存、电池和 GPU 计数器。

如需详细了解如何在 Unity 中对游戏进行性能分析,请访问 Unity 网站,观看视频 Introduction to profiling in Unity 或阅读文档 Ultimate guide to profiling Unity games

内存管理

Android 进程共享目标设备上的可用内存。如果目标测试设备有充足的可用内存资源,您应当分析内存用量。请在游戏中一致的点执行内存测试,这样才能恰当地比较会话和内存用量趋势。

使用 C# 编写脚本时,请慎用字符串、字符串比较和字符串相关对象(例如用于游戏设置的 JSON 文件)分配。这些用途需要频繁分配内存,并有可能导致内存碎片化。

请考虑优先使用 StringBuilder 类进行大型字符串序列操作,而原位字符串串联次之(例如 "this" + "is" + "a" + "bad" + "idea" 与 StringBuilder.Concat() 函数调用)。

如需详细了解字符串,请参阅 Unity 文档中的 Strings and text

请根据首选的 ScriptableObject 类型评估 TextAsset 和 JSON 文本资源。ScriptableObjects 可高效处理跨场景数据存储,并支持从编辑器到游戏时的修改。

如需查看有关使用默认 JSON 句柄的替代方案针对移动设备进行优化的探讨,请参阅 Hutch 上的 The hidden optimization in network games 一文。

请使用 Memory Advice API 确定运行时的内存用量。该 API 提供一个信号灯指示器,用于指示内存用量高、正常还是低。您可以订阅该指示器以获取更新,也可以直接轮询该指示器以获取当前状态。如果收到红色信号,请考虑减少游戏对象池或缓存。在游戏发布后的在线运营和性能指标审核期间,请将此上下文添加到游戏遥测中。

如需更深入地了解 Android 设备上的内存组织方式以及 Unity 的处理方式,请观看 Understanding Android memory usage(2018 年 Google I/O 大会演讲)。该视频详细介绍了内存问题的类型以及低内存终止守护进程何时奏效。

垃圾回收

受管内存环境中的垃圾回收可以清理可供应用回收的未使用内存碎片。请遵循垃圾回收最佳实践,避免不必要的内存资源分配。

例如,创建游戏对象池而不是使用按需分配 (GameObject.Instantiate)。如果是大型游戏对象池,可以考虑跨多帧分配,从而降低游戏在入门级 Android 设备上无响应的风险。

考虑从 MonoBehaviour 开头调用的以下简单协程代码段:

// Option 1: Bad for memory management - causes allocation each iteration
IEnumerator UpdateEnemyTarget() {
  while (enabled) {
    yield return new WaitForSeconds(1.0f);
    // Some intermittent function check
  }
}

// Option 2: Better for memory management - allocation of yield instruction once, reused each iteration
private YieldInstruction waitForSecond = new WaitForSeconds(1.0f);
IEnumerator BetterUpdateEnemyTarget() {
  while (enabled) {
    yield return waitForSecond;
    // Some other intermittent function
  }
}

您可以修改 MonoBehaviour 模板文件以移除 Start()Update() 桩函数,避免在开发时无意中留下空函数。

如需简要了解 MonoBehaviour 事件的执行顺序,请参阅 Unity 文档中的 Order of execution for event functions。如需详细了解内存管理,请参阅 Memory Management in Unity 课程。

如需有关如何优化移动游戏性能的提示,请参阅 Optimize your mobile game performance: Tips on profiling, memory, and code architecture from Unity's top engineers

预制件池

CPU 帧时间峰值几乎完全是由游戏过程中的预制件实例化导致的。请考虑在进入游戏前预热用于弹药、可刷出敌人和视觉效果的对象池,以减少或消除启动 CPU 高峰。其他优化则可以分布到加载期间或场景开场序列的多个“初始化帧”中。

您可以在 Unity Asset Store 中找到许多与游戏对象池管理相关的第三方池资源,也可以自行创建池资源。请参阅 Unity Learn 网站上的 Introduction to Object Pooling

资源分发

首次将应用部署到 Google Play 时,应用的大小会受到限制。根据游戏的大小和性质,您可能需要分发部分或全部游戏资源(角色模型、环境、界面元素等)才能让玩家获享您预期的体验。

您可以使用 Play Asset Delivery (PAD) 服务来管理游戏在安装时分发、快速跟进式分发或按需分发时所需的资源。为了支持 PAD,已集成 Unity Asset Bundle,您可以使用该工具指定要分发的元素。

Addressables

如果您准备了 Addressables 命名系统并用它进行查看,那么在运行时设置预制件、纹理和声音文件等动态资源将不再是一项复杂的操作。Addressable 资源将内容的排列方式与内容的构建和加载方式分离开来。Addressables 系统用于取代 Resources 文件夹和 Asset Bundle,旨在简化运行时的资源引用和加载方式。

如需查看示例,请参阅 GitHub 上的 Demo project using Addressables package。如需详细了解 Addressables 的开发,请参阅 Unity Blog 网站上的博文 Addressable Asset System

采用 Addressable 资源布局有利有弊,您可能会将太少或太多资源捆绑到通用资源包中。如需详细了解如何使用 Addressables 进行内容管理,请参阅 Simplify your content management with Addressables

您可以设置一个独立演示版并尝试各种访问模式,以便熟悉 Addressables 系统。您还可以查看开源项目 BuildLayout Explorer for Unity 2019.3 and newer 并查看 Addressables 生成的 buildlayout.txt 报告。

Unity 开源项目 Chop Chop 的资源使用 Addressables 系统打包,以便进行所有加载和卸载操作。如需查看演示,了解配置 Addressables 资源包时的结构和设置,请参阅 Packaging content with Addressable Assets | Open Projects Devlog

在 Chop Chop 项目中,默认加载的唯一场景是初始化场景,该场景被配置为使用 AssetReferences,而不是直接链接到项目中的资源(场景、预制件等)。

GitHub 上提供了 Unity Open Project: Chop Chop 的源代码。尽管该项目已不再处于开发阶段,但 Git 代码库和文档仍然可用。

第三方插件

如果您使用第三方插件(例如 Unity Asset Store 中的插件),请务必查看相关文件夹并从 Resources 文件夹中移除不必要的资源。在构建过程中,Unity 会收集 Resources 文件夹中包含的所有资源,并将其打包到单个可在运行时访问的资源包中。这可能会使最终软件包出现通常不必要的膨胀。

若要快速找到所有资源文件夹,请在 Project 面板中搜索 Resources。然后,您可以选择每个文件夹,以确定其中包含哪些资源,以及您的游戏是否需要该文件夹。

图 7. 从 Unity Asset Store 下载的文件夹中可能暗藏多个 Resources 文件夹。请清理这些资源,以免将其打包到应用软件包中。

发布和维护

当您准备好发布移动游戏后,您需要确定要向谁发布游戏、如何执行 Alpha 版和 Beta 版测试,以及如何在发布后监控和跟踪性能。

分析通过小范围发布收集的反馈

您可以面向目标受众群体进行小范围发布,并执行更大范围的 Beta 版测试,或激活游戏以在所有市场全面发布。通过小范围发布,您可以根据更广泛的实时受众群体和设备集合来调整应用性能。

例如,您可以使用 Android Performance Tuner (Unity)Unity 版 Google Analytics(分析)来深入了解应用性能和玩家趋势,然后您的开发团队便可根据这些信息调整和推送更新。您还可以使用分析数据来规划续作或类型相似的相关游戏。

Alpha 版和 Beta 版测试

Google Play 管理中心设置应用配置文件后,您可以准备 Alpha 版和 Beta 版公开测试 build,并将其分发给有限的受众群体进行发布前审核。面向受众群体进行小范围发布可以借助数量更多的设备解决最后剩下的任何问题并收集初始反馈,以便在全球发布上线前做出回应。

您的 Unity build 通过 Android App Bundle 分发。如需了解相关信息,请参阅 Unity 网站中的 Manual: Delivering to Google Play,该文档还介绍了从 APK 文件更改为 AAB 格式的变更。

监控和跟踪

在游戏的 LiveOps 和分发阶段,您可以使用 Android Vitals 帮助跟踪设备上那些在开发和测试期间可能无法接触到的性能问题。如需了解详情,请观看 What's new for games in Reach and devices and Android vitals

通常,规模较大的开发团队具有独特的自定义游戏遥测流水线,可提供与设备性能相关的指标。请务必利用 Android Performance Tuner (APT) 和相应的 Unity 插件来测量和优化与帧速率、图形保真度、加载时间和加载放弃率相关的指标。请按照 Integrating Android Performance Tuner into your Unity game 中的分步指南操作。

游戏上线后,游戏的生命周期并不会就此终止。想要让您的游戏令用户满意、受到好评并在所有市场获得最终采用,对性能和反馈进行监控、维护和响应有着至关重要的意义。