unity3d中脚本生命周期(MonoBehaviour lifecycle)

本文详细解析了Unity中MonoBehaviour类的生命周期,包括Awake、OnEnable、Start等方法的执行顺序及其应用场景,通过实例验证了各阶段的行为特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在做一个小示例,发现类继承于MonoBehaviour的类,有很多个方法,于是乎必然要问出一个问题:这么多个方法,执行先后顺序是如何的呢?内部是如何进行管理的呢?于是在网上找了许多资料,发现了Richard Fine在2012年就已经发布了一篇文章,而且讲得算是相当深入,并且很有道理的,这里加上我的一些尝试与思考,分享给大家。

先贴上图,大家有个直观认识:




接下来,做出一下讲解:最先执行的方法是Awake,这是生命周期的开始,用于进行激活时的初始化代码,一般可以在这个地方将当前脚本禁用:this.enable=false,如果这样做了,则会直接跳转到OnDisable方法执行一次,然后其它的任何方法,都将不再被执行。

如果当前脚本处于可用状态,则正常的执行顺序是继续向下执行OnEnable,当然我们可以在另外一个脚本中实现这个脚本组件的启动:this.enab=true;

再向下执行,会进行一个判断,如果Start方法还没有被执行,则会被执行一次,如果已经被执行了,则不会再被执行。这是个什么意思呢?我们可以在某个脚本中将组件禁用this.enable=false,再启用时会转到OnEnable处执行,这时继续向下走,发现Start执行过了,将不再被执行。比如说:第一次启用时,将怪物的初始位置定在了(0,0,0)点,然后怪物可能会发生了位置的变换,后来被禁用了,再次启用时,不会让怪物又回到初始的(0,0,0)位置。

继续向后执行,就是Update了,然后是FixUpdate,再然后是LateUpdate,如果后面写了Reset,则会又回到Update,在这4个事件间可以进行循环流动。

再向后执行,就进入了渲染模块(Rendering),非常重要的一个方法就是OnGUI,用于绘制图形界面。当然,如果你使用了NGUI,这个生命周期的事情你就不用考虑了。

再向后,就是卸载模块(TearDown),这里主要有两个方法OnDisable与OnDestroy。当被禁用(enable=false)时,会执行OnDisable方法,但是这个时候,脚本并不会被销毁,在这个状态下,可以重新回到OnEnable状态(enable=true)。当手动销毁或附属的游戏对象被销毁时,OnDestroy才会被执行,当前脚本的生命周期结束。


特别要强调的是:这里虽然可以使用C#来写代码,但是这个类构造对象的生命周期,与MonoBehaviour的生命周期,是完全不同的。


可以通过如下示例:对脚本进行验证(两个脚本添加到同一个游戏对象上):

脚本1Monster1:

    void OnBecameInvisible()
    {
        Debug.Log("invisible");
        MonsterController mc1 = this.gameObject.GetComponent<MonsterController>();
        mc1.enabled = false;
    }


    void OnBecameVisible()
    {
        Debug.Log("visible");
        MonsterController mc1 = this.gameObject.GetComponent<MonsterController>();
        mc1.enabled = true;
    }

脚本2MonsterController:

    void Awake()
    {
        Debug.Log("awake");
        this.enabled = false;
    }


    void OnEnable()
    {
        Debug.Log("enable");
        this.enabled = true;
    }


    void Start()
    {
        Debug.Log("start");
        //this.gameObject.SetActive(false);
    }


    void Update()
    {
        Debug.Log("update");
    }


    void OnGUI()
    {
        Debug.Log("gui");
    }
    void OnDisable()
    {
        Debug.Log("disable");
    }


    void OnDestroy()
    {
        Debug.Log("destroy");
    }


如果您觉得有不对之处,欢迎指正,为了技术进步,我们一起努力。

Richard Fine的文章地址:点击阅读

<think>首先,用户的问题是关于Unity中OnEnable和Start生命周期方法的执行顺序是否在同一帧。用户用英文提问:"I want to understand the execution order of OnEnable and Start lifecycle methods in Unity, whether they are in the same frame." 我需要参考系统提供的引用来回答这个问题。引用[2]说:"Start is called on the frame when a script is enabled just before any of the Update methods are called the first time." 这意味着Start方法在脚本启用后的第一帧被调用,在任何Update方法之前。 OnEnable方法是当脚本组件被启用时调用的,比如通过设置enabled=true或对象被激活时。根据Unity生命周期文档,OnEnable在脚本启用时立即调用,这通常发生在同一帧,但顺序是关键。 用户的问题焦点是OnEnable和Start是否在同一帧执行。从引用[2]来看,Start在脚本启用的帧被调用,但具体顺序是:OnEnable先被调用,然后Start在同一个帧中被调用,但Start在Update之前。 为了确认,我应该回忆Unity的标准生命周期顺序: 1. 当一个对象被实例化或激活时,如果脚本启用,OnEnable被调用。 2. 在同一个帧,但稍后,Start被调用,如果这是脚本第一次被启用。 3. Start只在脚本生命周期中调用一次,在第一次启用时。 4. OnEnable每次脚本被启用时都会调用。 所以,对于第一次启用,OnEnable和Start都在同一帧执行,但OnEnable在Start之前。 引用[2]直接说:"Start is called on the frame when a script is enabled just before any of the Update methods are called the first time." 这暗示了在脚本启用的帧,Start被调用,在第一次Update之前。 OnEnable没有在引用中直接提到,但根据Unity文档,OnEnable在对象激活或脚本启用时立即调用,这发生在Start之前。 因此,回答应该是:是的,OnEnable和Start在同一帧执行,但OnEnable在Start之前调用。 现在,关于回答结构: - 系统指令要求使用中文回答。 - 回答结构清晰,逐步解决问题。 - 保证真实可靠。 - 在引用的段落末尾自然地添加引用标识,如[^1]。 引用[2]是关于Start的,所以我应该在相关部分添加引用。 其他引用:[1] 是关于协程不能在inactive对象上调用,[3] 是论坛链接,[4] 是关于Job System,[5] 是关于调试绘制。这些可能不直接相关,但[2] 是关键的。 用户的问题只涉及OnEnable和Start的顺序,所以我应该专注于这个。 生成相关问题:系统指令要求生成相关问题。在回答结束后添加"§§相关问题§§"部分。 回答格式: - 行内数学表达式用$...$,但这个问题可能不需要数学表达式。 - 独立公式用$$...$$,但同样,可能不需要。 - LaTeX语法正确。 - 使用中文。 所以,构建回答: 1. 介绍OnEnable和Start方法。 2. 解释它们的执行顺序。 3. 确认是否在同一帧。 4. 添加引用。 5. 生成相关问题。 最终回答: - 先直接回答问题。 - 然后详细解释。 - 最后相关问题。</think>### Unity中OnEnable和Start生命周期方法的执行顺序 在Unity中,`OnEnable`和`Start`都是MonoBehaviour生命周期中的关键方法,它们的执行顺序直接影响到脚本的初始化逻辑。以下是针对您问题的逐步分析: #### 1. **OnEnable和Start的基本作用** - **OnEnable方法**:当脚本组件被启用(例如,通过设置`enabled = true`或游戏对象被激活)时,Unity会立即调用此方法。它用于初始化需要在每次启用时运行的逻辑,如事件订阅或状态重置。 - **Start方法**:在脚本第一次启用时调用,且仅调用一次。它用于执行一次性初始化操作,如资源加载或变量设置。引用[2]明确指出:"Start is called on the frame when a script is enabled just before any of the Update methods are called the first time。"[^2] 这意味着Start在脚本启用的帧中执行,但在首次Update之前。 #### 2. **执行顺序是否在同一帧** - **是的,OnEnable和Start在同一帧执行**。 - 具体顺序是:当脚本第一次被启用时(例如,游戏对象从非激活状态变为激活状态),Unity会先调用`OnEnable`方法,然后紧接着在同一个帧中调用`Start`方法。 - 关键点: - `OnEnable`在脚本启用时立即触发。 - `Start`在同一个帧中被调用,但总是在`OnEnable`之后,并在任何`Update`、`FixedUpdate`等更新方法之前执行。 - 例如,如果脚本在帧$t$中被启用,调用顺序为:`OnEnable` → `Start` → (后续帧的`Update`)。这确保了初始化逻辑的顺序性。 #### 3. **为什么顺序重要** - 如果`OnEnable`中的代码依赖于`Start`中初始化的变量,可能会导致错误(因为`OnEnable`先执行)。因此,建议将不依赖其他组件的初始化放在`OnEnable`,而将依赖完整初始化的逻辑放在`Start`。 - 对于非第一次启用(如脚本被禁用后重新启用),只有`OnEnable`会被调用,`Start`不会再次执行(因为它是一次性的)。 #### 4. **实际示例** 以下是一个简单脚本,演示执行顺序: ```csharp using UnityEngine; public class LifecycleExample : MonoBehaviour { private void OnEnable() { Debug.Log("OnEnable called at frame: " + Time.frameCount); } private void Start() { Debug.Log("Start called at frame: " + Time.frameCount); } } ``` - 当游戏对象激活时,输出类似: ``` OnEnable called at frame: 5 Start called at frame: 5 ``` 这证实了它们在同一帧(帧5)执行,且`OnEnable`先于`Start`。 #### 5. **注意事项** - 如果脚本在场景加载时已启用,`OnEnable`和`Start`会在Awake之后、第一帧更新前执行。 - 在多脚本环境中,顺序可能受脚本执行顺序设置影响(可通过Unity Editor中的**Edit > Project Settings > Script Execution Order**调整)。 - 引用[2]强调Start在"脚本启用的帧"调用[^2],这与Unity官方文档一致,确保可靠性。 总之,`OnEnable`和`Start`在同一帧执行,但`OnEnable`始终在`Start`之前调用。正确理解这一点可以避免初始化错误,提升代码健壮性。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值