Unity中的简单事件系统

我试图在Unity中使用事件系统(C#方式),但我遇到了实现它的问题。

大多数示例显示了一个类,您可以在其中定义处理程序; 然后你在相同的类中编写,匹配处理程序签名的函数,并将事件写为静态

public class EventExample : MonoBehaviour { public delegate void ExampleEventHandler(); public static event ExampleEventHandler OneDayPassed; public static void NextTurn() { // do stuff then send event if (OneDayPassed != null) OneDayPassed(); } } 

然后在另一个类中,您订阅事件,创建一个实际执行某些操作的函数

 public class EntityWatcher: MonoBehaviour { void Start() { EventExample.OneDayPassed += this.PrepareNextDay; } public void PrepareNextDay() { // Do other stuff that happen after the day is done } } 

到目前为止没有问题,但我不知道如何设计这个,所以任何特定类型的GameObject都会订阅此事件。 例如,如果你有一个GO职员类别,那就是工作8到6,你在运行时实例化它们; 我应该订阅这个类别的主类,还是应该创建一个附加到游戏对象预制件的脚本,订阅该事件?

目标是所有应该在体育中心进行8到6class的工作人员,知道“完成日期”事件何时启动,但我不想订阅我实例化的每一个预制件。

根据我的理解,我应该在预制件上添加一个带有所需代码的脚本,但我找不到一个实际的例子来说明这是否实际上是这样做的。

您必须使用UnityEvent

  public UnityEvent whoa; 

这可不容易。 制作一个脚本BigScript.cs

 using UnityEngine; using System.Collections; using UnityEngine.Events; public class BigScript:MonoBehaviour { [Header("Here's a cool event! Drag anything here!")] public UnityEvent whoa; } 

把它放在游戏对象上。 现在在Inspector中查看它 。 好吧?

只需将其他脚本拖到那里,就可以在发生“哇哇”的时候发生一些事情。

在此处输入图像描述

就这么简单。 要在BigScript中调用事件,它就是

 public class BigScript:MonoBehaviour { [Header("Here's a cool event! Drag anything here!")] public UnityEvent whoa; private void YourFunction() { whoa.Invoke(); } 

(如果你愿意, if (whoa!=null) whoa.Invoke();


在极少数情况下,您可能需要通过代码添加侦听器。

(我的意思是,而不是简单地在编辑器中拖动它。)

现在这很简单。 请注意互联网上过时的示例代码。

 whoa.AddListener(ScreenMaybeChanged); 

要明确: 永远不要那样做 – 只需拖动即可连接。 我只是提到完整性。


这里的所有都是它的。

请注意互联网上有关此主题的过时示例代码。*


以上显示了如何连接没有参数的简单函数。

如果你确实需要一个参数:

函数具有ONE FLOAT参数的示例:

只需在文件顶部添加此代码:

 [System.Serializable] public class _UnityEventFloat:UnityEvent {} 

那你就定了。

 ... using UnityEngine.Events; // magic line of code... [System.Serializable] public class _UnityEventFloat:UnityEvent {} public class SomeThingHappens : MonoBehaviour { public _UnityEventFloat changedLength; public _UnityEventFloat changedHeight; ... and then ... void ProcessValues(float v) { .... if (changedLength != null) changedLength.Invoke(1.4455f); } } 

当您从其他function拖动到此function的编辑器插槽时:

绝对确保使用顶部的那些 – “动态浮动”。

在此处输入图像描述

令人困惑的是,您的function也将列在较低的“静态参数”部分中!

这是团结中的巨大骗局!

如果你只谈几十个,不要太担心订阅者的数量。 是的,一旦你进入数百或数千,优化它可能是一个好主意,但即便如此。 优化的第一条规则:不优化。

所以:只需让每个实例订阅该事件并完成它。