c# - 运行所有 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 方法?我希望得到比我的方法更好的解决方案:
- X 秒后调用此方法(计时器很危险)
- 运行一次更新方法(我认为不好的解决方案)
- 编写一个系统来跟踪每个 EventSubscriber 并在每个 EventSubscriber 启动它的 Start 方法后触发第一个方法(这个逻辑太多了,不是吗?)
- 定义脚本执行顺序(我认为不好的解决方案)
解决方案
在统一文档上...
仅当启用脚本实例时,才会在第一帧更新之前调用 Start。
基于此,您可以使用协程等到开始时的下一帧,如下所示:
public class LevelReader : MonoBehaviour
{
// ...
void Start()
{
StartCoroutine(ReadLevelFileAfterFirstFrameCoroutine());
}
private IEnumerator ReadLevelFileAfterFirstFrameCoroutine()
{
yield return new WaitForEndOfFrame();
// Call read level file.
}
// ...
}
只需确保脚本实例实际上已按照文档状态启用。
如果需要,也可以调用协程Awake
。毕竟它会运行Awake
并被Start
调用。
推荐阅读
- amazon-quicksight - 对不同的数据集使用一个快速查看仪表板(从一项分析创建)
- logging - 将日志写入缓冲区,然后稍后使用 serilog 将缓冲区转储到另一个记录器?
- python - 使用“if”对列表的元素进行子集化
- java - 尝试在流 java 8 中捕获
- php - 如何访问在 PHP 中的函数和方法中动态创建的变量?
- rest - IIS 应用程序池用户无法访问 UNC 驱动器
- r - 如何从本地到远程服务器运行 RScript
- arduino - 使用 MIT App Inventor 读取蓝牙数据
- python - 类引用的类型提示是什么?
- spring - 入站通道适配器抛出“没有可用的输出通道或回复通道标头”错误