Unity对象初始化同步

Unity object initialization synchronization

直到现在,我一直认为 monobehaviour 中的函数将按以下顺序执行:

OnEnable > Start > Update > OnDisable

问题是我认为这个顺序是绝对,这意味着直到一个功能没有完全完成,下一个功能才会开始执行。

  1. 所以第一个问题是:这是真的吗?在 start 结束之前 update 不会被执行吗?

然后我的问题出现在不同 monobehaviour classes 之间的同步。

我有一个 class 可以在其 start 函数中创建一些对象(基本上是一个菜单)。然后在另一个 class 中,我有一个类似的代码,但它也 依赖于 由第一个 class 创建的对象已经存在。我收到错误消息,因为尚未找到该对象。

NullReferenceException: Object reference not set to an instance of an object ShopHandler.Start () (at Assets/Scripts/Shops/ShopHandler.cs:60)

所以现在我坚持这个。因此我的第二个问题是,

  1. 当我的不同 class 像这样依赖其他 时,我如何才能 同步它们?

最后,还要问一个混合这两个问题的问题:

  1. update 函数是否会在这些 class 中的任何一个中执行,而它们的初始化部分不知何故 "waiting",无论是在 start 函数中, OnEnable 功能还是什么?

因为当然,update 函数依赖于已经初始化的对象,这可能会导致新问题。

提前致谢

很难说你的问题到底出在哪里,因为你没有发布任何代码。但是,我相信您的问题可能会通过实施 2

中注明的解决方案来解决
  1. 是的,所有启动函数(和唤醒)在更新函数之前被调用,如果游戏对象/单体行为是enabled/active! Start/Awake/Update 不会在非活动游戏对象上调用

  2. 你应该看看 Script Execution Order。在这里,您可以确保 类 的启动/唤醒/更新功能按特定顺序调用。它应该列在项目设置下。

  3. 初始化场景时,更新将在所有唤醒/启动函数完成后调用(除非它们被定义为协程,但这可能不是你的问题)。

The problem is that I thought that this order would be absolute, meaning that until a function is not completely finished, there's no way that the next one would start being executed.

So first question is: Is that true? Would update NOT be executed until start ends?

通常是,但有例外。

如果将 Start 实现为协同程序,则可以在 Start 结束相同的单一行为之前调用 Update

例如,这段代码:

IEnumerator Start() 
{
    Debug.Log("Start beginning");
    
    yield return null;

    Debug.Log("Start continuing");

    yield return null;

    Debug.Log("Start completing");    
}

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

可以产生这个输出:

Start beginning
Start continuing
Update running
Start completing
Update running
Update running
Update running
...

这是我的方法:

假设您有两个单一行为 A 和 B。假设 B 必须在 A 之后初始化。那么;

1-) 创建一个函数,即 "Initialise" 并在 B 中使用它而不是 Start 函数:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class B : MonoBehaviour
{

    public void Initialise()
    {
        //Code you run on Start()    
    }

}

2-) 在A obj中引用B obj,准备初始化后使用bObj.Initialise:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class A : MonoBehaviour
{
    public B bObj;
    // Start is called before the first frame update
    void Start()
    {
        //Things to do in Start()
        //...
        //...
        //...
        bObj.Initialise();
    }

}

最后,如果您想随时使用更新功能 运行,我通常更喜欢使用一些东西作为标志。所以这是我的 class B 的第二个版本,用于控制 update() 行为:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class B : MonoBehaviour
{
    public bool canUpdate;
    public void Initialise()
    {
        //Code you run on Start()
        canUpdate = true;    
    }
    private void Update()
    {
        if (canUpdate)
        {
            //do the stuff
        }
    }

}