Unity对象初始化同步
Unity object initialization synchronization
直到现在,我一直认为 monobehaviour
中的函数将按以下顺序执行:
OnEnable > Start > Update > OnDisable
问题是我认为这个顺序是绝对,这意味着直到一个功能没有完全完成,下一个功能才会开始执行。
- 所以第一个问题是:这是真的吗?在
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)
所以现在我坚持这个。因此我的第二个问题是,
- 当我的不同 class 像这样依赖其他 时,我如何才能 同步它们?
最后,还要问一个混合这两个问题的问题:
-
update
函数是否会在这些 class 中的任何一个中执行,而它们的初始化部分不知何故 "waiting",无论是在 start
函数中, OnEnable
功能还是什么?
因为当然,update
函数依赖于已经初始化的对象,这可能会导致新问题。
提前致谢
很难说你的问题到底出在哪里,因为你没有发布任何代码。但是,我相信您的问题可能会通过实施 2
中注明的解决方案来解决
是的,所有启动函数(和唤醒)在更新函数之前被调用,如果游戏对象/单体行为是enabled/active! Start/Awake/Update 不会在非活动游戏对象上调用
你应该看看 Script Execution Order
。在这里,您可以确保 类 的启动/唤醒/更新功能按特定顺序调用。它应该列在项目设置下。
初始化场景时,更新将在所有唤醒/启动函数完成后调用(除非它们被定义为协程,但这可能不是你的问题)。
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
}
}
}
直到现在,我一直认为 monobehaviour
中的函数将按以下顺序执行:
OnEnable > Start > Update > OnDisable
问题是我认为这个顺序是绝对,这意味着直到一个功能没有完全完成,下一个功能才会开始执行。
- 所以第一个问题是:这是真的吗?在
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)
所以现在我坚持这个。因此我的第二个问题是,
- 当我的不同 class 像这样依赖其他 时,我如何才能 同步它们?
最后,还要问一个混合这两个问题的问题:
-
update
函数是否会在这些 class 中的任何一个中执行,而它们的初始化部分不知何故 "waiting",无论是在start
函数中,OnEnable
功能还是什么?
因为当然,update
函数依赖于已经初始化的对象,这可能会导致新问题。
提前致谢
很难说你的问题到底出在哪里,因为你没有发布任何代码。但是,我相信您的问题可能会通过实施 2
是的,所有启动函数(和唤醒)在更新函数之前被调用,如果游戏对象/单体行为是enabled/active! Start/Awake/Update 不会在非活动游戏对象上调用
你应该看看
Script Execution Order
。在这里,您可以确保 类 的启动/唤醒/更新功能按特定顺序调用。它应该列在项目设置下。初始化场景时,更新将在所有唤醒/启动函数完成后调用(除非它们被定义为协程,但这可能不是你的问题)。
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
}
}
}