我如何让某些功能可以在没有事件的情况下订阅(就像Unity那样)
本文关键字:情况下 事件 那样 Unity 就像 功能 | 更新日期: 2023-09-27 18:03:01
在Unity中,当你制作一个新的MonoBehaviour
类时,它带有一个完整的函数负载,你可以很容易地挂钩-例如Update()
, FixedUpdate()
和Awake()
。我正在制作自己的组件实体系统,并试图添加一系列可以轻松地由我创建的组件连接到的功能。我已经使我的基类抽象,并有Update
和Draw
作为抽象函数,然后可以继承。除了所有组件必须实现所有这些功能之外,这工作得很好;像Initialize这样的东西对某些组件有用,但对其他组件没用,我不确定如何模拟这种行为。
是用反射完成的吗?
您可以将方法定义为抽象,而可以将它们定义为虚拟,并仅在必要时重写。
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在这方面的"魔法方法"。我认为执行interfaces
或overriding virtual functions
通常是一个更清晰的解决方案。我曾经使用Unity的方法,用于AI插件,它应该调用用户定义的方法,而不必强制扩展类(基本上是因为我必须避免在修改AI行为时重新编译代码)
在任何情况下,关于实现:
1)发送消息
SendMessage使用纯反射实现:只有在调用SendMessage
时才能知道目标方法的名称。这似乎很方便(也许是这样,我从来没有使用过,也觉得没有必要使用),但是有几个缺点:
- 性能:反射是昂贵的(检查一些基准测试,它最终比直接方法调用慢数百倍)
- 不是类型安全的:不能在编译时检查传递的参数是否为正确的类型。
2) MonoBehaviour Messages
这些方法(如Awake
, Update
, OnCollision
,…)略有不同,因为Unity可以知道签名并编译委托。(我不确定实现,但我做过类似的事情)。
本文很好地描述了实现类似功能的方法。基本上,您只在初始化时使用反射,但是一旦获得MethodInfo
,您可以将该方法编译为具有Delegate.CreateDelegate
的委托。
结果:
- 你仍然使用反射,但只在初始化
- 一旦编译,委托几乎和标准方法调用(或事件)一样快。