Unity3D MonoBehaviour的生命周期(lifecycle)

官方的事件函数的执行顺序中有详解(Link:Execution Order of Event Functions

 

(图片来源:http://whatiseeinit.blogspot.com/2012/10/unity3d-monobehaviour-lifecycle.html

 

通过实际操作来测试上述的流程:

1、新建一个场景:LifecycleTest

2、在同级目录下新建一个C#脚本:LifecycleTest.cs,代码如下:

using System;
using UnityEngine;

[ExecuteInEditMode]
public class LifecycleTest : MonoBehaviour {

    private void Awake()
    {
        Debug.Log("Awake" + DateTime.Now.ToString());
    }

    private void Reset()
    {
        Debug.Log("Reset" + DateTime.Now.ToString());
    }

    private void OnEnable()
    {
        Debug.Log("OnEnable" + DateTime.Now.ToString());
    }

    private void OnDisable()
    {
        Debug.Log("OnDisable" + DateTime.Now.ToString());
    }

    private void OnDestroy()
    {
        Debug.Log("OnDestroy" + DateTime.Now.ToString());
    }


    // Use this for initialization
    void Start () {
        Debug.Log("Start" + DateTime.Now.ToString());
    }
    
    // Update is called once per frame
    void Update () {
        Debug.Log("Update" + DateTime.Now.ToString());
    }
}

3、将LifecycleTest.cs脚本拖拽至LifecycleTest场景的主相机(Main Camera)上(或者选中主相机,在检视图 — Inspector 中最底部按钮 Add Component,输入“LifecycleTest”然后回车,将选中的脚本附加到主相机中);

4、此时,控制台上将能看到相应的输出

Awake –> OnEnable –> Reset –> Start –> Update

1

 

当场景卸载时(比如双击切换到另一个场景时,当前场景会被卸载 – unload),此时会触发:

OnDisable –> OnDestroy

当场景被载入时(load)

Awake –> OnEnable –> Start –> Update

当C#脚本被修改时(Modified)时

OnDisable –> OnEnable

 

我们会发现上面有二对相对应的函数:

Awake —— OnDestroy

OnEnable —— OnDisable

卸载时是 OnDisable –> OnDestroy,加载时是 Awake –> OnEnable。

 

 

注意动态创建的实例对象,记得显示设置隐藏标记(HideFlags)以便更加准确控制其生命周期,避免报错或其它意外的发生。

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
    // Creates a material that is explicitly created & destroyed by the component.
    // Resources.UnloadUnusedAssets will not unload it, and it will not be editable by the inspector.
    private Material ownedMaterial;
    void OnEnable()
    {
        ownedMaterial = new Material(Shader.Find("Diffuse"));
        ownedMaterial.hideFlags = HideFlags.HideAndDontSave;
        GetComponent<Renderer>().sharedMaterial = ownedMaterial;
    }

    // Objects created as hide and don't save must be explicitly destroyed by the owner of the object.
    void OnDisable()
    {
        DestroyImmediate(ownedMaterial);
    }
}

 

HideFlags的值为枚举类型,详细的参数请参考官网>>

<think>嗯,用户想要了解在Unity中设置MonoBehaviour生命周期事件的最佳实践,并需要代码示例。首先,我需要回顾一下Unity生命周期函数,比如Awake、Start、Update这些的顺序和用途。根据引用[1]里的信息,调用顺序是Awake -> OnEnable -> Start,然后是Update、FixedUpdate、LateUpdate等。这些函数的正确使用对于代码的高效运行很重要。 用户需要最佳实践的代码示例,所以我应该分不同阶段来讲解。比如,在初始化阶段,Awake适合用于组件引用和变量初始化,而Start则适合处理依赖其他组件的逻辑。比如在Awake里获取组件,然后在Start里进行需要这些组件的操作。 然后,更新阶段有Update、FixedUpdate和LateUpdate。FixedUpdate用于物理相关的更新,而LateUpdate可能在摄像机跟随中使用,确保在所有Update之后执行。需要举例说明,比如在LateUpdate中更新摄像机位置。 事件响应阶段,比如OnEnable和OnDisable,可以用于注册和注销事件,避免内存泄漏。例如,在OnEnable里订阅事件,OnDisable里取消订阅。 销毁阶段,OnDestroy用于资源释放,比如停止协程或断开网络连接。这里要提醒用户注意资源管理,避免泄露。 另外,用户可能还会关心如何选择正确的生命周期函数,如引用[1]提到的第4点。所以需要给出一些实践建议,比如避免在Update中进行昂贵操作,区分Awake和Start的使用场景等。 代码示例方面,要确保每个函数都有对应的例子,比如在Awake里获取组件,在Start里初始化依赖,在OnEnable里注册事件。同时,代码格式要正确,使用$$...$$来包裹独立公式,但这里可能更多是代码块,所以用三个反引号包裹。 最后,生成相关问题,比如如何优化生命周期函数的使用,处理脚本执行顺序等,这样用户可以有进一步了解的途径。需要确保引用标识正确,比如引用[1]、[2]、[3]对应的内容。 检查是否覆盖了所有生命周期阶段,并提供了实际的代码示例,确保最佳实践的建议明确,比如变量初始化放在Awake,依赖处理在Start,事件处理在OnEnable/OnDisable。同时提醒避免常见错误,如在Update中频繁实例化对象。 总结起来,结构应该是分阶段讲解,每个阶段给出最佳实践和代码示例,然后给出注意事项和相关问题。这样用户能清晰地理解如何正确使用各个生命周期函数。</think>### UnityMonoBehaviour生命周期事件最佳实践代码示例 #### 1. 初始化阶段 ```csharp using UnityEngine; public class LifecycleDemo : MonoBehaviour { private Rigidbody _rb; private bool _isInitialized; // Awake:用于初始化独立变量和组件引用 private void Awake() { _rb = GetComponent<Rigidbody>(); // 获取组件引用 Debug.Log("Awake: 组件初始化完成"); } // OnEnable:激活时执行(可重复触发) private void OnEnable() { EventManager.OnGameStart += HandleGameStart; // 事件订阅 Debug.Log("OnEnable: 已注册游戏开始事件"); } // Start:初始化依赖其他组件的逻辑 private void Start() { if (_rb != null) _rb.mass = 5f; // 依赖物理组件的设置 _isInitialized = true; Debug.Log("Start: 初始化完成"); } } ``` **最佳实践**: - 在$Awake()$中获取组件引用和初始化独立变量[^3] - 在$Start()$中执行需要其他组件完成初始化的操作[^1] - 通过$OnEnable()$进行事件订阅,避免重复注册[^2] --- #### 2. 更新阶段 ```csharp // FixedUpdate:物理相关更新(固定时间步长) private void FixedUpdate() { if (_isInitialized) { _rb.AddForce(Vector3.up * 0.5f); // 物理引擎相关操作 } } // Update:常规游戏逻辑更新 private void Update() { if (Input.GetKeyDown(KeyCode.Space)) { FireProjectile(); // 输入响应 } } // LateUpdate:摄像机跟随等后期处理 private void LateUpdate() { UpdateCameraPosition(); // 保证在角色移动后更新 } ``` **最佳实践**: - 物理操作严格放在$FixedUpdate()$[^1] - 输入检测放在$Update()$[^2] - 需要延迟执行的逻辑使用$LateUpdate()$[^3] --- #### 3. 事件响应阶段 ```csharp // OnDisable:对象禁用时执行 private void OnDisable() { EventManager.OnGameStart -= HandleGameStart; // 取消事件订阅 Debug.Log("OnDisable: 已注销游戏开始事件"); } // OnDestroy:对象销毁时执行 private void OnDestroy() { StopAllCoroutines(); // 停止协程 Debug.Log("OnDestroy: 资源已释放"); } ``` **最佳实践**: - 必须成对实现$OnEnable()$/$OnDisable()$的事件管理[^1] - 在$OnDestroy()$中释放非托管资源[^3] --- #### 4. 高级实践(协程管理) ```csharp private Coroutine _damageCoroutine; private void TakeDamage() { if (_damageCoroutine != null) StopCoroutine(_damageCoroutine); _damageCoroutine = StartCoroutine(DamageEffect()); } private IEnumerator DamageEffect() { // 实现伤害效果逻辑 yield return new WaitForSeconds(1f); } ``` **最佳实践**: - 使用协程引用控制长时间运行的任务 - 在对象禁用时自动停止协程 --- ### 注意事项 1. 避免在$Update()$中执行昂贵操作(如$GameObject.Find$) 2. 脚本执行顺序可通过`Edit > Project Settings > Script Execution Order`调整 3. 使用$[RequireComponent(typeof(Rigidbody))]$属性确保组件依赖
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值