C# 统一的简单事件系统
我试图在Unity(C#方式)中使用事件系统,但在实现它时遇到了问题 大多数示例都显示了一个类,您可以在其中定义处理程序;然后在同一个类中编写与处理程序签名匹配的函数,并将事件作为静态事件编写C# 统一的简单事件系统,c#,events,unity3d,C#,Events,Unity3d,我试图在Unity(C#方式)中使用事件系统,但在实现它时遇到了问题 大多数示例都显示了一个类,您可以在其中定义处理程序;然后在同一个类中编写与处理程序签名匹配的函数,并将事件作为静态事件编写 public class EventExample : MonoBehaviour { public delegate void ExampleEventHandler(); public static event ExampleEventHandler OneDayPassed;
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
}
}
到目前为止还没有问题,但我不确定如何设计它,因此任何特定类型的游戏对象都将订阅此事件。例如,如果您有一个职员类别GO,即工作8到6,并且您在运行时实例化它们;我应该在这个类别的主类中订阅,还是应该创建一个附加到游戏对象预制的脚本来订阅事件
我们的目标是让所有应该在体育中心轮班8到6次的工作人员知道“一天结束”活动何时开始,但我不想订阅我实例化的每一个预制件
据我所知,我应该在预置中附加一个脚本,其中包含所需的代码,但我找不到一个实际的例子来说明这是否是实现的方法。如果您只谈论几十个订阅者,请不要太担心订阅者的数量。是的,一旦你进入成百上千,优化这个可能是一个好主意,但即使如此。优化的第一条规则:不要优化
因此:只需让每个实例订阅事件并完成它。您必须使用
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;
}
把它放在游戏物体上。现在在检查器中查看它
您将看到“哇”事件
当“哇”发生时,只需将其他脚本拖到那里,就可以在其他脚本上发生一些事情。
就这么简单。要在BigScript中调用事件,只需
[Header("Here's a cool event! Drag anything here!")]
public UnityEvent whoa;
private void YourFunction()
{
whoa.Invoke();
}
在极少数情况下,您可能需要通过代码添加侦听器,而不是简单地在编辑器中拖动它。这是微不足道的:
whoa.AddListener(ScreenMaybeChanged);
(通常情况下,您不必这样做。只需拖动即可连接。我只是为了完整起见才提到这一点。)
就这些 请注意internet上有关此主题的过时示例代码
上面显示了如何连接没有参数的简单函数 如果您确实需要一个参数: 下面是一个示例,其中函数有一个浮点参数: 只需在文件顶部添加以下代码:
[System.Serializable] public class _UnityEventFloat:UnityEvent<float> {}
[System.Serializable]公共类_UnityEventFloat:UnityEvent{}
然后继续正常操作。就这么简单
// ...
using UnityEngine.Events;
// add this magic line of code up top...
[System.Serializable] public class _UnityEventFloat:UnityEvent<float> {}
public class SomeThingHappens : MonoBehaviour
{
// now proceed as usual:
public _UnityEventFloat changedLength;
void ProcessValues(float v)
{
// ...
changedLength.Invoke(1.4455f);
}
}
/。。。
使用UnityEngine.Events;
//将这行神奇的代码添加到顶部。。。
[System.Serializable]公共类_UnityEventFloat:UnityEvent{}
公共课发生了一些事情:单一行为
{
//现在照常进行:
公共单位即使不允许更改长度;
无效处理值(浮点v)
{
// ...
changedLength.Invoke(1.4455f);
}
}
从其他函数拖动到此函数的编辑器插槽时:
一定要使用“动态浮动”部分
(令人困惑的是,您的函数也将列在“静态参数”部分中!这在Unity中是一个巨大的gotchya!)嗨,Newb'z。这完全是错误的。现在你只需使用
UnityEvent
。你不使用,实际上也不能使用十年前的“旧式”事件。因此,与语言本身的一部分相比,依赖于只在统一中使用的东西更好?嗨@newbiez。是的,这是绝对正确的。你应该明白,你在使用统一,你在使用传统编程的极端扭曲。它不是一个面向对象的系统,它是ECS。考虑一下我最近的问题,Unity有这些“接口”,它们实际上是完全错误的,而C接口中的“接口”是相反的。我不明白。我看过的其他地方都说原生C#events优于UnityEvent,即使在这里,然后这里有一个比较显示原生C#events在这里更好:但奇怪的是,这个问题和评论以及所有的答案现在都在说UnityEvent更好?我完全糊涂了。谢谢Joe,这比使用标准的C#委托和事件系统要简单得多。我唯一担心的是,一旦你习惯了这一点,你就会失去标准的C#方式来做事情……我确实为Unity应用程序和纯C#应用程序编写代码,所以我的“to go”方法通常是使用C#提供的任何本机代码。我假设Unity方法与使用C#中的常规委托和事件一样有效;谢谢嗨,newbiez,传统的c#事件在Unity环境下不起作用,因为它是一个ECS系统。因此,Unity创建了(杰出的)UnityEvent系统。考虑到你在多个系统上工作这一事实——没什么大不了的。你必须是这两方面的专家。这就是生活!我懂了;我确实使用带有事件和委托的常规C#代码实现了我的系统,但这要容易得多,并且与Unity中的其他所有东西一样,与ECS模型兼容。事实上,您必须是一个万事通:)问题:我想了解的是,在使用派生的UnityEvent
类型(例如,公共类CustomEvent:UnityEvent
)时,如何在检查器中指定参数值。使用此选项时,检查器会理解签名(字符串、浮点),允许在目标脚本中选择要调用的函数,但不允许在检查器中为这些参数指定值。将stockUnityEvent
绑定到采用字符串
参数的函数时,此功能可用。也许没有自定义编辑代码是不可能的?Howdy@PaulBinder(1)当然,在某些情况下,您可以在代码(2)中进行编辑。我在上面的上下文中回答了这个问题