c# - 运行所有 Start 方法后创建事件链

标签 c# unity3d

我正在尝试开发一个事件驱动的游戏。起初我创建了一个带有一堆事件的单例,例如与当前关卡相关的所有事件。

public class LevelEvents : MonoBehaviour
{
    public static LevelEvents instance;

    public event Action onLevelRead;
    public event Action onLevelSerialized;

    private void Awake()
    {
        instance = this;
    }

    public void LevelRead()
    {
        if (onLevelRead != null)
        {
            onLevelRead();
        }
    }

    public void LevelSerialized()
    {
        if (onLevelSerialized != null)
        {
            onLevelSerialized();
        }
    }
}

我想创建一个从读取关卡文件到序列化关卡的事件链。所以这些事件似乎非常简单。

enter image description here

我的 LevelReader 是入口点并在读取文件后调度事件。

public class LevelReader : MonoBehaviour
{
    void OnEnable()
    {
        SceneManager.sceneLoaded += ReadLevelFile;
    }

    private void OnDestroy()
    {
        SceneManager.sceneLoaded -= ReadLevelFile;
    }

    private void ReadLevelFile(Scene scene, LoadSceneMode loadSceneMode)
    {
        // not implemented yet
        LevelEvents.instance.LevelRead();
        Destroy(gameObject);
    }
}

序列化器将监听事件并序列化关卡。之后,它将为下一个脚本调度序列化事件

public class LevelSerializer : MonoBehaviour
{
    private void Start()
    {
        LevelEvents.instance.onLevelRead += SerializeLevel;
    }

    private void OnDestroy()
    {
        LevelEvents.instance.onLevelRead -= SerializeLevel;
    }

    private void SerializeLevel()
    {
        // not implemented yet
        LevelEvents.instance.LevelSerialized();
        Destroy(gameObject);
    }
}

那么问题来了。读取器在场景加载后调度读取事件。序列化程序将在启动时监听此事件。为时已晚,序列化程序将不会收到通知。我不能使用 Awake,因为这是事件单例注册 (LevelEvents) 所必需的。

想过不监听sceneLoaded事件,在Start方法中调用ReadLevelFile方法。这仍然为时已晚,因为 LevelReader 的 Start 方法被触发,Serializer 仍然不会收到通知。

如何在触发每个 Start 方法后运行 ReadLevelFile 方法?我希望得到比我的方法更好的解决方案:

  • 在 X 秒后调用此方法(计时器很危险)
  • 运行一次 Update 方法(我认为这是一个糟糕的解决方案)
  • 编写一个系统来跟踪每个 EventSubscriber 并在每个 EventSubscriber 启动其 Start 方法后触发第一个方法(这个逻辑太多了,不是吗?)
  • 定义脚本执行顺序(我认为这是一个糟糕的解决方案)

最佳答案

关于 unity docs ...

Start is called before the first frame update only if the script instance is enabled.

基于此,您可以使用协程等待下一帧开始,如下所示:

public class LevelReader : MonoBehaviour
{
    // ...

    void Start()
    {
        StartCoroutine(ReadLevelFileAfterFirstFrameCoroutine());
    }

    private IEnumerator ReadLevelFileAfterFirstFrameCoroutine()
    {
        yield return new WaitForEndOfFrame();
        // Call read level file.
    }

    // ...
}

只需确保脚本实例实际已启用,如文档所述。
如果需要,您也可以在 Awake 中调用协程。它将在所有 AwakeStart 被调用后运行。

关于c# - 运行所有 Start 方法后创建事件链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57543674/

相关文章:

ios - 由于着色器警告和编译器因 XPC_ERROR_CONNECTION_INTERRUPTED 而失败,Unity 应用程序无法在 iOS 上运行

android - 如果我将代码块写在 "UNITY_EDITOR"中,Unity 是否会将代码块包含在 apk 中

c# - 如何在不旋转的情况下改变Unity中VerticalLayoutGroup的扩展方向?

c# - 在保留堆栈跟踪和内部异常信息的同时抛出新异常

c# - 上传带有 MD5 哈希结果的流在 "The Content-MD5 you specified was invalid"

c# - 如何减少 ""中涉及的内存和操作量 找到添加到 N"面试挑战的所有对?

c++ - Mathf.SmoothDamp() 如何工作?它是什么算法?

c# - 使用反射在谓词中引用类的属性

c# - 如何使用 linq to entities 对所有按月记录求和?

c# - Unity GameObject 速度和动画问题