☰
UnityEvent
2026/10/1 21:55:48 网站建设 项目流程

简介:

定位:为可视化而生;

方法注册:所有类型(无参或者泛型)的UnityEvent都支持静态注册无参和单参方法(参数类型授限)。静态注册即在inspector面板上配置;

参数传递:静态传递只支持单参数方法,多参数必须在Invoke中动态传递。

1.Inspector配置/纯代码绑定

对于UnityEvent的使用,根据是否需要Inspector可视化配置分为两种声明方式。

1.1 Inspector配置

在 Unity 中声明带参数的UnityEvent主要通过‌继承泛型类‌来实现。

由于UnityEvent的泛型版本(如UnityEvent<T>)是抽象类或需要在 Inspector 中序列化,因此不能直接在字段中声明为new UnityEvent<int>()并期望其在编辑器中完美工作。

步骤一:定义自定义事件类

你需要创建一个继承自UnityEvent<T0, T1...>的新类,并加上[System.Serializable]特性,以便在 Unity 编辑器的 Inspector 面板中显示和配置。必须添加[System.Serializable]特性,否则该事件可能无法在 Inspector 中正确显示持久化监听器(Persistent Listeners)。

注:[System.Serializable]加在类或结构体定义上,标记“这个类能被序列化”,[SerializeField]管“字段”,标记“这个私有字段要参与序列化并显示在 Inspector”‌。

using UnityEngine; using UnityEngine.Events; //支持一个参数 [System.Serializable] public class IntEvent : UnityEvent<int> { } //支持四个参数 [System.Serializable] public class MyCustomEvent : UnityEvent<string, int, bool, float> { }

步骤二:在 MonoBehaviour 中使用

在你的脚本中声明上述自定义类的公共字段。

public class EventExample : MonoBehaviour { // 在 Inspector 中可以看到这个字段,并可以添加监听者 //此处声明后并未初始化,应该是Unity在inspector生成中进行了初始化 public IntEvent onScoreChanged; void Start() { // 代码动态添加监听 onScoreChanged.AddListener(HandleScoreChange); } void Update() { if (Input.GetKeyDown(KeyCode.Space)) { // 触发事件,传入参数 onScoreChanged.Invoke(100); } } // 监听方法,签名必须与泛型参数匹配 void HandleScoreChange(int score) { Debug.Log("Current Score: " + score); } }

将脚本添加至游戏对象,则在inspector面板中,可看到如下设置界面

1.2 纯代码方式(不需要Inspector配置)

如果你‌不需要‌在 Unity 编辑器的 Inspector 面板中绑定事件(即所有监听器都通过代码动态添加),那么你可以‌不创建子类‌,直接使用泛型实例。

using UnityEngine; using UnityEngine.Events; public class CodeOnlyEvent : MonoBehaviour { // 直接声明泛型字段,无需创建子类 private UnityEvent<int> myEvent = new UnityEvent<int>(); void Start() { // 必须通过代码添加监听 myEvent.AddListener(HandleNumber); // 触发 myEvent.Invoke(42); } void HandleNumber(int num) { Debug.Log(num); } }

‌缺点‌:

  • 在 Inspector 中不可见。
  • 无法保存持久化监听器(Persistent Listeners)。
  • 通常用于纯代码架构或临时事件。

1.3 测试疑问?

针对inspector配置须通过‌继承泛型类‌来实现这个说法,在以下测试代码中发现直接声明UnityEvent字段在inspector中也是可编辑和配置的呀??有点懵了。

此外,并不需要去做初始化,关于这个的解释如下:对于public或[SerializeField]标记的这些受支持类型,Unity 会在序列化阶段自动实例化它们,所以即使你不写= new UnityEvent<int>(),它也不会为 null,且在 Inspector 中可见。

using UnityEngine.UIElements; using UnityEngine; using UnityEngine.Events; public class EventExample : MonoBehaviour { // 在 Inspector 中可以看到这个字段,并可以添加监听者 public IntEvent onScoreChanged; public UnityEvent onTest; public UnityEvent<int> onTest2; public UnityEvent<PlayerData> onTest3; public UnityEvent<int,float> onTest4; private void Awake() { } void Start() { if (onTest != null) { Debug.Log("OnTest initialize"); } if (onTest2 != null) { Debug.Log("OnTest2 initialize"); } if (onTest3 != null) { Debug.Log("OnTest3 initialize"); } if (onTest4 != null) { Debug.Log("OnTest4 initialize"); } // 代码动态添加监听 onScoreChanged.AddListener(HandleScoreChange); } void Update() { if (Input.GetKeyDown(KeyCode.Space)) { // 触发事件,传入参数 onScoreChanged.Invoke(100); } } // 监听方法,签名必须与泛型参数匹配 void HandleScoreChange(int score) { Debug.Log("Current Score: " + score); } } [System.Serializable] public class IntEvent : UnityEvent<int> { } [System.Serializable] public struct PlayerData { public int id; public string name; }

2. 使用 C# 原生Action/Delegate(替代方案)

如果你觉得 UnityEvent 的声明太繁琐,且不需要 Inspector 可视化,可以使用 C# 原生的Action或event。这在代码层面更简洁,但功能不同。

using System; using UnityEngine; public class ActionExample : MonoBehaviour { // 声明简单,支持任意数量参数 public event Action<int, string> OnDataReceived; void Trigger() { // 触发前检查 null OnDataReceived?.Invoke(100, "Hello"); } }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询