Ludo Atlas · 引擎轨道 · Unity¶
引擎轨道。定位:Unity 轨道工程手册,覆盖组件心智模型、脚本生命周期、数据资产、包生态、版本控制与多平台构建。 配套:《技术实现手册》·《美术与音频手册》·《制作管理手册》·《小游戏开发手册》。
1. 定位与选型¶
一句话定位:Unity 是组件化、C# 脚本驱动、生态存量最大的通用引擎。它不挑游戏类型,挑团队工程能力:编辑器把拼装成本压得很低,项目一大,结构、性能与协作的问题全要自己兜住。
适合:
- 中小团队与独立开发者的第一款商业作品:文档、问答、教程的检索成本在同类引擎里最低。
- 一次开发、多平台发行:桌面、移动、主机、Web 共用一套工程与内容。
- 2D 与中低模 3D 项目:2D 工作流与 3D 管线在同一编辑器里,混合项目不用换工具。
- 玩法与数值迭代频繁的原型:编辑器内改完立即验证,循环很短。
需要三思:
- 高保真 3D 与超大场景:这是 Unreal 的主场,别用工程成本硬扛美术缺口。
- 极致轻量的 2D 小项目:Godot 或 Web 技术栈的工程面更小。
- 深度改造引擎底层:Unity 核心闭源,可定制的是上层,底部动不了。
跨引擎取舍收口成四行(其余轨道见 docs/engines/):
| 项目画像 | 常规选择 |
|---|---|
| 通用商业项目、需要招人与外包生态 | Unity(本页) |
| 要求完全开源、愿意读改引擎源码 | Godot 或自研引擎 |
| 高保真 3D、大团队工业流程 | Unreal |
| 纯 Web 交付、页面级轻量玩法 | Web 技术栈 |
选型检查清单:
- 目标平台里有没有 Web 或小游戏?有,先验证包体与加载,再决定(§3.3)。
- 谁维护构建与版本控制?没有专人,先把 §2.4 的约定立起来。
- 这是 2D 还是 3D 项目?决定后统一相机、光照与素材规格,不要两种做法混着来。
- 团队的 C# 与架构水平如何?Unity 项目的主要技术债来自代码组织,不是引擎本身。
2. 生态与工程结构¶
2.1 工程目录结构¶
| 目录 | 内容 | 进版本库 | 说明 |
|---|---|---|---|
Assets/ |
场景、脚本、Prefab、材质、模型、音频等项目内容 | 是 | 工作区,全部内容产在这里 |
Packages/ |
依赖清单与本地嵌入包 | 清单与本地包进 | 依赖用清单声明,不要手动拷贝源码充当依赖 |
ProjectSettings/ |
渲染、输入、物理、质量等工程级配置 | 是 | 团队协作的一部分,改动要评审 |
Library/、Temp/、Logs/ |
导入缓存、临时文件与日志 | 否 | 本机可重建,提交只会制造冲突与噪音 |
2.2 组合心智模型¶
- GameObject 是空容器,本身没有任何功能;功能全部由挂上去的组件提供:渲染、碰撞、音频、自定义脚本都是组件。
- 一切组合都是往容器上拼零件:一个角色等于变换、碰撞、动画加若干行为脚本。没有继承树,只有拼装,所以「这个功能放哪」的答案通常是「新写一个小组件」。
- 场景是对象的运行舞台,同时承担摆放与串联的角色。把场景当配置与挂载表,重逻辑不要长在场景里。
- Prefab 是可复用的对象模板:在场景里搭出原型,存成资产,再从模板实例化。支持嵌套(Prefab 里含 Prefab)与变体(从基础 Prefab 派生出差异配置)。
- 心智模型一句话:组件是零件,Prefab 是图纸,场景是装配现场。可复用的行为进组件与 Prefab,一次性的摆放留在场景。
2.3 包管理与工具生态¶
- 官方能力按包模块化提供:用到才装,工程里「装了哪些包、为什么装」要能一句话说清,不用的定期清理。
- 包有四个来源:官方注册表、资产商店、Git 地址、本地路径。第三方包进工程前评估五件事:体积、编译时间、许可证、维护状态、能否只取需要的部分。
- 包污染是 Unity 工程最隐蔽的成本:一个大而全的资产包会同时抬高导入时间、编译时间与包体,还带来自己的目录结构、样例场景和旧依赖。纪律是先隔离试用,评审通过再进主工程。
- 官方云服务(分析、云存档、多人中继等)按需接入,选型时就要评估替换成本。
- 工具生态:IDE 集成(补全与调试)、编辑器脚本(把重复操作做成菜单命令)、单元测试与 Play 模式测试、性能分析工具(§5)。任何被手动做过三次的流程,都值得脚本化。
2.4 版本控制约定¶
Unity 工程与普通代码仓库的差异集中在两件事上:资产是二进制,而引用靠伴随文件。
- 文本序列化:把资产序列化模式设为文本,场景与 Prefab 变成可读、可 diff、冲突可合并的文本文件。这是多人协作的前提,建仓第一天就切,别等出事了再补。
.meta文件:每个资产与文件夹配一份.meta,记录唯一标识与导入设置。三条规矩:随资产一起提交;只通过编辑器改名与移动(编辑器外的改名与移动会切断引用);不要手工编辑或删除。- Git LFS:纹理、音频、模型、视频、字体走大文件存储,仓库里只留指针。忽略清单从官方模板起步,
Library/、Temp/、Logs/与构建产物一律不进库。 - Smart Merge:官方提供的合并工具,在拉取与合并时对场景与 Prefab 的文本冲突做结构级合并。它只能处理语法层面的冲突,语义冲突(两人改了同一对象的不同属性)仍要人工判断。真正的解法是减少同名文件的并发编辑。
- 协作纪律:按模块拆场景与 Prefab,避免多人同改一个大场景;提交信息写清改了什么行为与资产。
3. 核心工作流¶
3.1 编辑器里的日常循环¶
日常节奏:场景里拼装 → 进 Play 模式验证 → 退出后改脚本与资产 → 再进 Play 模式。三条纪律:
- Play 模式里的修改不会保留:把 Play 模式当只读的观察窗口,记录问题,回到编辑态再改资产。
- 复现问题用最小场景:从主场景剥出只含相关对象的测试场景,不要在完整关卡上调试。
- 重复操作脚本化:批量改导入设置、批量生成资产、批量检查命名,都写成编辑器脚本一次执行。
3.2 场景与 Prefab 工作流¶
标准路径:白盒场景 → 识别重复对象 → 抽成 Prefab → 用嵌套与变体管理差异 → 场景只留摆放与少量有意覆盖。
- 场景分层:环境(静态)、玩法对象(Prefab 实例)、系统(相机、管理器、光源)用根节点分开,谁都能看懂这棵树的形状。
- 抽 Prefab 的时机:同一个对象第二次出现时。出现第三次还在复制粘贴,就是给自己埋债。
- 实例覆盖要克制:在场景里改 Prefab 实例的属性会生成覆盖项,被覆盖的属性不再跟随基础 Prefab 的更新。允许少量有意覆盖,禁止随手乱改。
- 变体处理同一原型的不同配置:不同数值的敌人、不同颜色的门这类差异用变体表达,不要复制一整棵子树。
- 拆场景的信号:多人开始互相阻塞、单个场景加载变慢、一个场景塞进互不相关的模块。到这一步,按区域或玩法切场景,用异步加载拼接。
3.3 构建与多平台¶
Unity 的构建模型是「选目标平台、出对应产物」,三个平台族的差异:
| 平台族 | 产物形态 | 主要约束 |
|---|---|---|
| 桌面 | 可执行文件与数据目录 | 存储路径与图形接口的差异;约束最松 |
| 移动 | 商店分发的应用包 | 发热与内存最紧;必须真机测;iOS 要求 AOT 编译 |
| Web | 浏览器加载的网页产物 | 首次加载体积与时间是生命线;浏览器沙箱限制线程与能力;移动浏览器更弱 |
- 脚本编译:目标平台不支持运行时编译(iOS、Web)时需要提前 AOT 编译,反射与动态生成代码的用法要早期验证,别等发版才暴露。
- 构建配置化:每个目标的包名、图标、签名、场景清单、质量档位都是工程配置,建仓时固化成多套配置,别在发版当天手填。
- 构建自动化:把构建做成命令行任务接进 CI,每次提交产出可玩版本(《技术实现手册》§6)。手动点菜单的构建只适合本机调试。
- Web 与小游戏:Web 构建盯首包加载时间,资源切分与懒加载是常规手段;国内小游戏平台没有原生构建目标,经 Web 构建加适配方案转换,包体与性能门槛更严。
- 多平台差异逐项打勾:输入方式、分辨率与安全区、平台生命周期(后台挂起与恢复)、权限弹窗、存储与云存档、字体与本地化(《全平台上架手册》的核对表可复用)。
4. 关键系统惯用法¶
4.1 脚本生命周期与执行顺序¶
生命周期回调是 Unity 编程的骨架。背下来不够,要理解两件事:谁在什么时候被调用,同一阶段里多个脚本的顺序不保证。
| 回调 | 时机 | 常见职责 |
|---|---|---|
| Awake | 对象被加载或实例化时一次(对象未激活则推迟) | 抓取自身组件引用、初始化内部状态 |
| OnEnable | 每次被激活时 | 订阅事件、注册到管理器 |
| Start | 首次激活后、第一次帧更新之前一次 | 需要别的对象已就绪的装配逻辑 |
| FixedUpdate | 按固定时间步调用,一帧可能零次或多次 | 物理与力学相关逻辑 |
| Update | 每帧一次 | 输入采样、非物理逻辑、表现驱动 |
| LateUpdate | 每帧在全部 Update 之后 | 相机跟随、依赖其他对象本帧位置的逻辑 |
| OnDisable / OnDestroy | 失活与销毁时 | 退订事件、归还对象池、释放资源 |
执行顺序意识:
- 同一阶段里,不同脚本之间默认没有稳定顺序。两个脚本在各自 Awake 里互相抓引用,谁先谁后全凭运气,现象是随机的空引用。
- 收敛方式有两种:把耦合的初始化收进一个显式的入口(由一个脚本按序发起),或在编辑器里声明脚本执行顺序。项目越大越要靠前者,声明顺序只适合少量特例。
- 跨阶段的坑:在 Awake 里读另一个对象 Start 阶段才准备好的数据;在 Update 里读物理结果,而物理其实在 FixedUpdate 里步进。
- 把「谁依赖谁」画成一张有向图:无环、入口单一、顺序可预测。图乱掉的项目会在启动阶段随机崩溃,且难以复现。
4.2 ScriptableObject:数据资产¶
ScriptableObject 是序列化在工程里的数据对象,作用是把数据从场景对象里抽出来:数值表、配置、敌人档案、事件通道。它解决三件事:多处引用同一份数据、编辑器里可视化编辑、避免每个实例复制一份。
- 数值与配置一律进数据资产:角色参数、关卡配置、经济表。散在场景与 Prefab 里的数值是维护灾难的源头。
- 以数据资产为中介解耦:触发方与订阅方各自引用同一个数据资产(事件通道),互相不认识,模块间通知不用硬引用。
- 运行时把它当只读:在编辑器里运行游戏时修改数据资产,改动会被写回资产本身,这是最常见的自坑方式;可变状态放进普通运行时对象。
- 数据资产是普通资产:可 diff、可批量脚本处理、可走评审,数值改动因此有了流程与历史。
4.3 系统惯用法清单¶
对照《技术实现手册》§2 的跨引擎清单,Unity 语境下各系统的落点:
- 输入:逻辑动作与物理按键分层,输入采样与固定物理步解耦,短按缓存按帧记账(《技术实现手册》§2.1)。
- 对象池:子弹、特效、敌人这类高频对象一律池化,预热到峰值数量;引擎自带的池化方案优先于手写。
- UI:数据与视图分离;把界面拆成多个画布单元,频繁变化的元素与静态元素分开,控制重建范围。
- 存档:只存状态不存对象引用;带版本号与迁移逻辑;写入先临时文件再替换,防中断坏档。
- 相机:跟随参数(前瞻、死区、缓动)与震屏限幅按《技术实现手册》§2.3 的清单执行,震屏必须可关闭。
- 本地化:可见文本全部外置成键值;文本区域按多语言长度预留;字体回退链覆盖中日韩字符。
5. 性能与优化要点¶
方法论继承《技术实现手册》§3:先定预算、先测后改、真机大于编辑器。Unity 项目多发的热点集中在五处:
| 热点 | 症状 | 对策 |
|---|---|---|
| 每帧回调总量 | 帧率随对象数上升持续下跌 | 用少数管理器合并驱动、事件代替轮询、按需启用 |
| 托管内存分配 | 周期性卡顿(垃圾回收停顿) | 消除热路径分配:字符串拼接、装箱、闭包、集合扩容;对象池 |
| 运行时查找 | 热点函数里全是查找调用 | 引用在初始化时抓一次并缓存;能用编辑器拖拽引用就不用代码查找 |
| 渲染提交 | GPU 等待、CPU 忙于提交 | 合批与图集、减少材质切换与半透明面积;用帧调试器定位真凶 |
| 物理与动画 | 大量刚体或高密度骨骼时掉帧 | 分层碰撞过滤、简化碰撞体、降低物理频率、控制骨骼与蒙皮层数 |
- 测量工具链:引擎 Profiler 看帧与内存,帧调试器看渲染提交,内存快照看资产驻留,平台性能工具做真机确认。编辑器数据常常失真,结论以真机为准。
- 预算表:帧预算按目标帧率切分到逻辑、渲染、物理、UI;内存预算分平台;包体预算分渠道。超预算就报警,能进 CI 更好。
- 移动端专项:发热降频(长时间运行后的帧率)、内存水位(被系统杀进程的风险)、包体积与下载转化;Web 专项:首包加载时间、浏览器内存上限、移动浏览器兼容矩阵。
- 优化纪律:一次只改一个变量,改前改后记录同一场景同一路径的数据;没有测量不做优化。
6. 学习路线¶
按产物分四段,每段的里程碑都是可玩或可用的东西,不是看完的教程数:
- 引擎基本功(2-4 周量级):C# 基础、编辑器操作、组件模型。做三个小游戏覆盖:2D 移动与碰撞、UI 流程、存档读写;每个都发一次 Web 构建,顺手打通构建链路。
- 系统实现(1-2 个月量级):对照《技术实现手册》§2 逐项做最小实现(输入、对象池、相机、存档、UI、音频、本地化),每项一个小 demo。这一段的产出是能力库,之后项目直接取用。
- 工程化(贯穿始终):版本控制约定(§2.4)、构建流水线、性能预算与测量习惯(§5)、关键逻辑的测试。选一段自己写的代码,用 Profiler 找出三个热点并优化到数据可证明。
- 完整项目:进《制作管理手册》的流程,把工程基建拉满,走一次完整发布。
学习纪律:官方手册是概念与行为的权威依据,教程只用于入门与找手感;本页给出的判断随生态演化,遇到分歧以官方文档与你的 Profiler 为准。
7. 常见坑¶
- GetComponent 滥用:在 Update 里找组件、在循环里找组件,开销直接进帧预算。引用在初始化时抓一次并缓存,能用编辑器拖拽引用的就不用运行时查找。
- Update 全量开销:成百上千个对象各自持有每帧回调,逻辑各干各的。把同质对象交给管理器合并驱动,或用事件与状态变化驱动,别让每个对象每帧都醒着。
- 第三方包污染:为一个小功能导入整包资产,换来成吨的无用资源、编译时间与依赖冲突。先隔离试用、评审、只取需要的部分,导入后清理样例与未用资产。
- 每帧分配引发卡顿:字符串拼接、装箱、闭包捕获、循环里建集合都会制造垃圾回收压力。热路径上一个分配都不要有,池化与缓存是常规手段。
- 版本控制三连错:把
Library/提交进仓库、手工删除或改名.meta、一直用二进制序列化。建仓当天就把 §2.4 的约定做完。 - 场景与 Prefab 的覆盖混乱:在场景里随手改 Prefab 实例的属性,改基础 Prefab 时行为不一致,谁改的都说不清。覆盖要有意识、有记录(§3.2)。
- 隐式依赖脚本执行顺序:靠「它应该先跑」来写初始化,现象是随机空引用。初始化收敛到显式入口或执行顺序设置(§4.1)。
- 只在编辑器里验证:编辑器帧率、输入与内存都与真机不同,移动端尤其。真机、目标机型、目标时长,三者缺一不算测过。
- 数据散落在场景里:数值直接写在组件上,改一个参数要满场景找。数据进数据资产(§4.2),场景只留摆放。
延伸阅读¶
- 《技术实现手册》:架构选型、核心系统、性能方法论与工程基建,本文 §4、§5 的完整展开。
- 《美术与音频手册》:资产规范、导入设置与表现反馈,涉及美术管线时对照。
- 《制作管理手册》:原型到发布的阶段模型与范围控制,第 6 节项目段的入口。
- 《小游戏开发手册》:各引擎导出小游戏的路线与包体约束,Web 与小游戏发布前必读。
- Unity 官方手册与脚本参考:概念与行为的权威依据;本页判断随生态演化,以官方文档与你项目的 Profiler 为准。