# 检视面板可配置的自定义事件

> Create your own custom events to configure persistent (lasting between Edit mode and Play mode) callbacks in the Inspector window.

Unity 提供了 [UnityEvent](/engine/6000.0/script-reference/unity-engine-events/unity-event.md) API 作为标准 C# [事件和委托](https://learn.microsoft.com/en-us/dotnet/standard/events/)的 Unity 特定替代方案。相比于标准 C# 事件，Unity 事件的主要优点在于 Unity 事件可序列化，这意味着可以在[检视面板 (Inspector) 窗口](/engine/6000.0/manual/unity-editor/using-the-editor/using-the-inspector.md)中配置它们。

`UnityEvent` 可以添加至任何 `MonoBehaviour`，并在运行时像标准 C# 委托一样执行。在 `MonoBehaviour` 中声明 `UnityEvent` 时，它会显示在**检视面板**窗口中，您可以在其中定义在编辑时间和运行时之间持续存在的回调。

Unity 事件具有与标准 C# 委托类似的限制：

* 它们会保留对目标对象的引用，而这会阻止对目标对象进行垃圾收集。
* 如果目标为托管 (C#) `UnityEngine.Object`，并且已销毁非托管 (C++) 对应对象，则不会调用回调。请参阅 [Null 引用](/engine/6000.0/manual/scripting/object-oriented-development/null-reference-exception.md)以了解更多上下文信息。

## 配置 Unity 事件

### 先决条件

* 创建包含 `using UnityEngine.Events` 的 MonoBehaviour 脚本
* 声明至少一个 `UnityEvent` 类型的字段

### 在检视面板窗口中配置回调：

1. 选择包含脚本组件的游戏对象，该脚本组件包含您声明的 `UnityEvent` 字段。

2. 单击事件名称下的 + 按钮可添加回调字段。

3. 选择要接收回调的 [UnityEngine.Object](/engine/6000.0/manual/scripting/get-started/fundamental-unity-types/class-object.md)。可以使用对象选择器或将对象拖放到字段中。

4. 选择要在事件发生时调用的函数。下拉选单中会填充游戏对象及其组件上可用的[适当方法](#static-dynamic-calls)的过滤列表。

5. 根据需要重复第 1-4 步，为同一事件添加其他回调。


**在检视面板窗口中为名为 Trigger Entered 和 Trigger Exited 的事件配置回调:**
![](/api/media?file=/engine/6000.0/media/images/unityevents-inspector.PNG)

### 静态和动态调用

在**检视面板**窗口中配置 `UnityEvent` 时，支持两种类型的函数调用：

* **静态**调用在创作时完全预先配置，其目标和参数值在检视面板窗口中定义。调用回调时，将使用检视面板中定义的参数值调用目标函数。这适用于在运行时不会改变的值，例如，每次发生特定碰撞时，您都会希望角色健康值减少固定的值。静态绑定的函数显示在函数选择列表中的**静态参数 (Static Parameters)** 下方。
* **动态**调用以编程方式从代码中调用，参数与调用的 `UnityEvent` 类型相匹配。这适用于在运行时变化的值，例如，表示角色在每次受攻击时承受的变化伤害量的 `float`。UI 会过滤回调，仅显示签名对 `UnityEvent` 类型有效的动态函数。例如，如果有 `UnityEvent<string>`，则函数选择器会在**动态字符串 (Dynamic string)** 标题下列出接受 `string` 参数的所有函数。


**选择签名与检视面板窗口中的事件类型相匹配的静态或动态函数:**
![](/api/media?file=/engine/6000.0/media/images/unityevents-dynamic-static.PNG)

## UnityEvent 中的泛型支持

默认情况下，`Monobehaviour` 中的 `UnityEvent` 动态绑定到 `void` 函数。但是，可以创建一个最多包含四个泛型类型参数的 `UnityEvent`，如下例所示：

```lang-csharp
using UnityEngine;
using UnityEngine.Events;

public class GenericTest : MonoBehaviour
{
    public UnityEvent<int, int, bool, string> myEvent;
    
    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        if (myEvent == null)
        {
            myEvent = new UnityEvent<int, int, bool, string>();
        }
        myEvent.AddListener(Ping);
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.anyKeyDown && myEvent != null)
        {
            myEvent.Invoke(5, 6, true, "Hello");
        }
    }

    void Ping(int i, int j, bool print, string text)
    {
        if (print)
        {
            Debug.Log("Ping: " + text + i + j);
        }
    }
}
```

## 其他资源

* [使用拖放事件设置门、触发器等](https://youtu.be/tmmvhxQcbJk)
* [UnityEvent API 参考](/engine/6000.0/script-reference/unity-engine-events/unity-event.md)
