我如何让某些功能可以在没有事件的情况下订阅(就像Unity那样)

本文关键字:情况下 事件 那样 Unity 就像 功能 | 更新日期: 2023-09-27 18:03:01

在Unity中,当你制作一个新的MonoBehaviour类时,它带有一个完整的函数负载,你可以很容易地挂钩-例如Update(), FixedUpdate()Awake()。我正在制作自己的组件实体系统,并试图添加一系列可以轻松地由我创建的组件连接到的功能。我已经使我的基类抽象,并有UpdateDraw作为抽象函数,然后可以继承。除了所有组件必须实现所有这些功能之外,这工作得很好;像Initialize这样的东西对某些组件有用,但对其他组件没用,我不确定如何模拟这种行为。

是用反射完成的吗?

我如何让某些功能可以在没有事件的情况下订阅(就像Unity那样)

您可以将方法定义为抽象,而可以将它们定义为虚拟,并仅在必要时重写

class BaseComponent : MonoBehaviour
{
    public virtual void OnAwesomeEvent()
    {
        // do nothing or implement default behaviour
    }
}
class ShinyComponent : BaseComponent
{
    public override void OnAwesomeEvent()
    {
        Debug.Log("I've been waiting for this!");
        // If you need the default implementation you can call it with
        // base.OnAwesomeEvent()
    }
}
class LazyComponent : BaseComponent
{
    // I do nothing and no one cares
}

免责声明:

我正在制作我自己的组件实体系统,我正在尝试添加一个可以很容易地通过组件I连接到的函数范围创建.

我不太喜欢unity在这方面的"魔法方法"。我认为执行interfacesoverriding virtual functions通常是一个更清晰的解决方案。我曾经使用Unity的方法,用于AI插件,它应该调用用户定义的方法,而不必强制扩展类(基本上是因为我必须避免在修改AI行为时重新编译代码)

在任何情况下,关于实现:

1)发送消息

SendMessage使用纯反射实现:只有在调用SendMessage时才能知道目标方法的名称。这似乎很方便(也许是这样,我从来没有使用过,也觉得没有必要使用),但是有几个缺点:

  1. 性能:反射是昂贵的(检查一些基准测试,它最终比直接方法调用慢数百倍)
  2. 不是类型安全的:不能在编译时检查传递的参数是否为正确的类型。

2) MonoBehaviour Messages

这些方法(如Awake, Update, OnCollision,…)略有不同,因为Unity可以知道签名并编译委托。(我不确定实现,但我做过类似的事情)。

本文很好地描述了实现类似功能的方法。基本上,您只在初始化时使用反射,但是一旦获得MethodInfo,您可以将该方法编译为具有Delegate.CreateDelegate的委托。

结果:

  • 你仍然使用反射,但只在初始化
  • 一旦编译,委托几乎和标准方法调用(或事件)一样快。