【问题标题】:Unity object initialization synchronizationunity 对象初始化同步
【发布时间】:2019-06-28 17:22:48
【问题描述】:

到目前为止,我一直在编写代码,认为monobehaviour 中的函数将按此顺序执行:

OnEnable > 开始 > 更新 > OnDisable

问题是我认为这个顺序是绝对的,这意味着在一个函数没有完全完成之前,下一个函数不可能开始执行。

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

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

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

NullReferenceException:对象引用未设置为对象 ShopHandler.Start () 的实例(在 Assets/Scripts/Shops/ShopHandler.cs:60)

所以现在我被困住了。因此,我的第二个问题是,

  1. 我如何在我的不同类依赖于其他类时同步它们

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

  1. update 函数是否会在这些类中的任何一个中执行,而它们以某种方式“等待”它们的初始化部分,无论是在 start 函数、OnEnable 函数还是其他什么中?

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

提前致谢

【问题讨论】:

  • 请在您的问题中包含错误和异常消息作为文本,而不是图像。将它们作为图片包含在内,使得通过搜索有类似问题的人更难找到问题,也使使用屏幕阅读器的人更难访问问题。
  • 另外,建议用多个部分分隔问题into separate posts.

标签: c# unity3d initialization


【解决方案1】:

这是我的方法:

假设您有两个单一行为 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();
    }

}

最后,如果您希望 Update 函数随时运行,我通常更喜欢使用某些东西作为标志。所以这是我用于控制 update() 行为的 B 类的第二个版本:

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
        }
    }

}

【讨论】:

  • 我在开始阅读该方法时期待某种开销,但它看起来相当干净(至少对我来说)。谢谢大佬。
  • 很高兴听到这个消息! ; )
【解决方案2】:

问题是我认为这个顺序是绝对的,这意味着在一个函数没有完全完成之前,下一个函数不可能开始执行。

所以第一个问题是:这是真的吗?直到开始结束才会执行更新吗?

通常是的,但有一个例外。

如果您将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");
}  

可以产生这个输出:

开始
开始继续
更新运行
开始完成
更新运行
更新运行
更新运行
...

【讨论】:

  • 为了澄清可以用(private) IEnumerator Start()替换普通的(private) void Start()吗?
  • internal 与不在 a/ 函数前面放置访问修饰符不同。私人是默认值。 (要检查这一点,您可以尝试在同一命名空间中使用或不使用 internal 修饰符从另一个类调用 start 方法,以查看差异)
  • 谢谢-@akaBase,是的,它们也可以受到公共或内部的保护
【解决方案3】:

很难说你的问题实际上来自哪里,因为你还没有发布任何代码。但是,我相信您的问题可以通过实施2 中提到的解决方案来解决

  1. 是的,所有启动函数(和唤醒)在更新函数之前被调用,如果游戏对象/单一行为被启用/激活!不活动的游戏对象不会调用开始/唤醒/更新

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

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

【讨论】:

  • 看起来不错。我要去看看它。会带着消息回来。谢谢!
猜你喜欢
  • 1970-01-01
  • 2013-06-27
  • 1970-01-01
  • 2020-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多