这篇只查生命周期怎么放代码:哪里缓存组件、哪里订阅事件、哪里做物理、哪里清理。
快速索引
| 我想做什么 |
生命周期 |
| 缓存自己身上的组件 |
Awake |
| 检查 Inspector 引用 |
Awake |
| 订阅事件 |
OnEnable |
| 取消事件 |
OnDisable |
| 读取其它对象初始化后的数据 |
Start |
| 普通每帧逻辑 |
Update |
| 输入检测 |
Update |
| Rigidbody 移动 |
FixedUpdate |
| 摄像机跟随 |
LateUpdate |
| 停止协程 / Tween |
OnDisable |
| 释放非 Unity 资源 |
OnDestroy |
| 对象池每次取出初始化 |
自定义 OnSpawn / Init |
| 对象池每次回收清理 |
自定义 OnDespawn / ResetState |
0. 执行顺序速记
1 2 3 4 5 6 7 8
| Awake # 对象创建后,本对象初始化 OnEnable # 对象启用,可能执行很多次 Start # 第一次 Update 前执行一次 FixedUpdate # 固定物理步长 Update # 每帧一次 LateUpdate # 每帧 Update 后 OnDisable # 禁用或销毁前,可能执行很多次 OnDestroy # 对象销毁时
|
1. Awake:缓存组件和本对象初始化
1 2 3 4 5 6 7 8 9 10 11 12
| private Rigidbody rb;
private void Awake() { rb = GetComponent<Rigidbody>();
if (rb == null) { Debug.LogError("缺少 Rigidbody", this); enabled = false; } }
|
适合:
1 2 3 4
| GetComponent 缓存 字段初始化 Inspector 引用检查 创建本对象内部依赖
|
不适合:
1 2 3
| 读取其它对象 Start 才初始化的数据 启动复杂游戏流程 做耗时加载
|
2. OnEnable / OnDisable:事件成对处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| private void OnEnable() { GameEvents.PlayerDied += OnPlayerDied; }
private void OnDisable() { GameEvents.PlayerDied -= OnPlayerDied; }
private void OnPlayerDied() { Debug.Log("玩家死亡"); }
|
UI 事件:
1 2 3 4 5 6 7 8 9
| private void OnEnable() { startButton.onClick.AddListener(OnStartClicked); }
private void OnDisable() { startButton.onClick.RemoveListener(OnStartClicked); }
|
少用:
1 2 3 4
| private void OnEnable() { startButton.onClick.AddListener(() => StartGame()); }
|
3. Start:跨对象初始化
1 2 3 4 5 6 7 8 9 10
| private void Start() { player = FindObjectOfType<Player>();
if (player == null) { Debug.LogError("场景中缺少 Player", this); enabled = false; } }
|
适合:
1 2 3
| 读取其它对象已经准备好的状态 场景初始对象查找 首帧前启动流程
|
仍然不建议依赖多个对象的 Start 顺序,严格顺序用 Bootstrap。
4. Update:每帧逻辑
1 2 3 4 5 6 7 8 9
| private void Update() { if (Input.GetKeyDown(KeyCode.Space)) { Jump(); }
cooldown -= Time.deltaTime; }
|
Update 里慎用:
1 2 3 4 5 6
| GameObject.Find # 每帧查找开销高 FindObjectOfType # 每帧查找开销高 GetComponent # 可提前缓存 new List / new Dictionary # 每帧分配 GC LINQ # 容易产生 GC Debug.Log # 刷屏卡顿
|
5. FixedUpdate:物理逻辑
1 2 3 4 5
| private void FixedUpdate() { Vector3 velocity = moveInput * moveSpeed; rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime); }
|
适合:
1 2 3
| Rigidbody.MovePosition Rigidbody.AddForce 物理检测
|
输入不要只放 FixedUpdate,可能漏按键;建议 Update 读输入,FixedUpdate 用输入结果。
6. LateUpdate:跟随和收尾
1 2 3 4 5 6 7 8 9
| private void LateUpdate() { if (target == null) { return; }
transform.position = target.position + offset; }
|
适合:
1 2 3
| Camera 跟随 角色动画后修正 依赖其它 Update 结果的同步
|
7. OnDestroy:最终释放
1 2 3 4 5
| private void OnDestroy() { saveHandle?.Dispose(); saveHandle = null; }
|
注意:
1 2 3 4
| OnDestroy 时其它单例可能已经销毁 事件解绑优先放 OnDisable 协程停止优先放 OnDisable 不要在 OnDestroy 里启动新流程
|
8. 对象池生命周期
1 2 3 4 5 6 7 8 9 10 11 12 13
| public void Init(int damage, Vector3 direction) { this.damage = damage; this.direction = direction; lifeTime = 3f; }
public void ResetState() { damage = 0; direction = Vector3.zero; lifeTime = 0f; }
|
对象池别只靠:
1 2
| Start # 只执行一次,第二次取出不会再跑 OnDestroy # 回收对象通常不会 Destroy
|
9. 生命周期模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public sealed class ExampleBehaviour : MonoBehaviour { private void Awake() { }
private void OnEnable() { }
private void Start() { }
private void Update() { }
private void FixedUpdate() { }
private void LateUpdate() { }
private void OnDisable() { }
private void OnDestroy() { } }
|
10. 常见坑速查
1 2 3 4 5 6
| Awake 读别人 Start 初始化的数据 # 顺序不稳定 OnEnable 订阅但 OnDisable 不取消 # 重复触发 / 旧对象响应 Update 每帧 FindObjectOfType # 性能差 FixedUpdate 里读 GetKeyDown # 可能漏输入 对象池只在 Start 初始化 # 第二次取出状态残留 OnDestroy 访问全局单例 # 单例可能已经销毁
|
系列导航