首页 > 解决方案 > 运行所有 Start 方法后创建事件链

问题描述

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

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();
        }
    }
}

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

在此处输入图像描述

我的 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 方法?我希望得到比我的方法更好的解决方案:

标签: c#unity3d

解决方案


统一文档上...

仅当启用脚本实例时,才会在第一帧更新之前调用 Start。

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

public class LevelReader : MonoBehaviour
{
    // ...

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

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

    // ...
}

只需确保脚本实例实际上已按照文档状态启用。
如果需要,也可以调用协程Awake。毕竟它会运行Awake并被Start调用。


推荐阅读