【问题标题】:Simple event system in UnityUnity 中的简单事件系统
【发布时间】:2016-03-27 06:48:17
【问题描述】:

我正在尝试在 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 到 6 班轮班的工作人员都知道“一天结束”事件何时启动,但我不想订阅我实例化的每一个预制件.

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

【问题讨论】:

  • 嗨,Newb'z。这完全是完全错误的。这些天你只使用UnityEvent。您不使用并且实际上不能使用十年前的“老式”事件。
  • 所以最好依赖仅在 Unity 中使用的东西,而不是语言本身的一部分?
  • 嗨@newbiez。是的,这绝对正确。
  • 您应该明白,当您使用 Unity 时,您使用的是传统编程的极端扭曲。它不是 OO 系统,而是 ECS。考虑一下我最近提出的这个问题,stackoverflow.com/questions/36251078/… unity 有这些“接口”,实际上完全是乱码,与 c# 中的“接口”相反。
  • 我不明白。我看过的其他地方都说原生 C# 事件优于 UnityEvent,即使在 stackoverflow.com/questions/44734580/… 上也是如此,然后这里有一个比较显示原生 C# 事件在这里更好:jacksondunstan.com/articles/3335 但奇怪的是这个问题和 cmets 以及所有答案现在都是说 UnityEvent 更好?我完全糊涂了。

标签: c# events unity3d


【解决方案1】:

您必须使用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 中查看它

您将看到“哇”事件。

只需将您的 other 脚本拖到那里,当“哇”发生时,在那些 other 脚本上发生一些事情。

就这么简单。要在 BigScript 中调用事件,只需

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

在极少数情况下,您可能需要通过代码添加侦听器,而不是简单地将其拖到编辑器中。这是微不足道的:

whoa.AddListener(ScreenMaybeChanged);

(通常您永远不必这样做。只需拖动即可连接。我只是为了完整起见而提到这一点。)


仅此而已。

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


上面展示了如何连接没有参数的简单函数

如果您确实需要参数:

这是一个函数具有 ONE FLOAT 参数的示例:

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

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

然后照常进行。就这么简单。

// ...
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);
    }
}

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

一定要使用“动态浮动”部分。

(令人困惑的是,您的函数也将在“静态参数”部分列出!这在 Unity 中是一个巨大的问题!)

【讨论】:

  • 感谢 Joe,这比使用标准 C# 代表和事件系统要简单得多。我唯一担心的是,一旦你习惯了这一点,你就会失去标准的 C# 做事方式......我确实为 Unity 应用程序和纯 C# 应用程序编写代码,所以我的“to-go”方法通常是使用无论 C# 原生提供什么。我假设 Unity 方法与在 C# 中使用常规委托和事件一样高效;谢谢!
  • 嗨新手,传统的 c# 事件在 Unity 上下文中不起作用,因为它是一个 ECS 系统。 出于这个原因 Unity 创建了(出色的)UnityEvent 系统。关于您在多个系统上工作的事实 - 没什么大不了的。你必须是这两个方面的专家。这就是生活!
  • 我明白了;我确实使用带有事件和委托的常规 C# 代码实现了我的系统,但这更容易,并且符合 ECS 模型,就像 Unity 中的其他所有东西一样。的确,你一定是个万事通 :)
  • 问题:我想了解的是,当使用派生的UnityEvent 类型(例如public class CustomEvent:UnityEvent&lt;string,float&gt;)时,如何在 Inspector 中指定参数的值。使用它时,Inspector 了解签名(字符串、浮点数),允许选择要在目标脚本中调用的函数,但不允许您在 Inspector 中为这些参数指定值。当将股票 UnityEvent 绑定到采用 string 参数的函数时,此功能可用。也许没有自定义编辑代码是不可能的?
  • 你好@PaulBinder (1) 当然,在某些情况下你会在代码中执行此操作 (2) 我在上面回答初学者时遇到了一些困惑:这是你“在代码中做的事情”;而特别是在讨论中的实际示例中,并且几乎总是,它与代码“无关”,您只需在检查器中单击它,所以我试图清除它。 ((3)关于你的具体情况,TBH 我不完全清楚你在做什么,所以我不知道!:) {natch,你可以在这里问另一个问题}干杯!
【解决方案2】:

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

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

【讨论】:

  • 同意;因为我以前没有在这类事情上使用 Unity,所以我想确保我以“正确”的方式进行操作。我没有太多事件,但我有数百个订阅这些事件的实体,因为我的应用程序中的所有实体都取决于某些周期的开始和结束时间(它们都是你的实例,所以应该很容易用 Unity 清除) .
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-06
  • 2011-08-03
  • 2018-06-15
  • 1970-01-01
  • 2020-12-27
相关资源
最近更新 更多