Unity事件系统(委托与回调函数)

1.理解事件系统

事件系统可以理解为,有一个呼叫者【唯一性】发出一种特定的信号(激活事件的函数),一个或多个监听者监听它所监听信号(事件注册/撤销),如果匹配则监听者会实施相应动作(回调函数)。

2.事件系统的整体框架

3.简易版事件系统

        1.事件中心

        event声明这是一个事件,提供注册订阅与撤销订阅的机制,组织外部直接触发事件。

        委托在c#中有四种:

                1.Action:无返回值的泛型委托

                2.delegate:可有可无返回值

                3.Func:有返回值的泛型委托

                4.Predicate:只有一个参数,返回值为bool

public static class EventHandler
{
    public static event Action<int> Event; //定义事件
    public static void CallEvent(int a) 
    {
        Event?.Invoke(a); //激活事件注册的回调函数
    }
}

        2.事件监听

                1.事件的注册/撤销放在OnEnable与OnDisable中,在启用和关闭脚本时进行注册/撤销

                2.回调函数:可以将其看作参数传入其他函数,并由其他函数控制执行时机。例如在事件系统中接收回调函数的函数是委托,委托相当于容器,里面存放着注册的回调函数。

                注:取消订阅是为了垃圾回收与防止空引用

public class EventListener : MonoBehaviour
{
    //注册事件
    private void OnEnable() 
    {
        EventHandler.Event += CallbackFunction;
    }

    //注销事件
    private void OnDisable() 
    {
        EventHandler.Event -= CallbackFunction;
    }

    //回调函数
    private void CallbackFunction(int a) 
    {
        Debug.Log(this + ":" + a);
    }
}

        3.事件呼叫

public class Caller : MonoBehaviour
{
    private void Awake() 
    {
        //呼叫事件
        EventHandler.CallEvent(30);
    }
}

4.进阶版事件系统 

        1.事件中心

                1.基类

                UnityAction是Unity定义的委托类型

public class BaseEventSO<T> : ScriptableObject
{
    [TextArea] public string description;
    
    public UnityAction<T> OnEventRaised;
    
    public void RaisEvent(T value)
    {
        OnEventRaised?.Invoke(value);//呼叫一般具有唯一性
    }
}

                2.实现类 

                注:创建对应的SO文件,一般传入参数不同需要创建不同实现类与该实现类的SO文件

[CreateAssetMenu(fileName = "ObjectEventSO", menuName = "Events/ObjectEventSO")]

public class ObjectEventSO : BaseEventSO<int>
{
    
}

        2. 事件监听

                1.基类

                UnityEvent类似于一个回调函数的集合并且可以在编辑器中可视化(对委托的封装)。

public class BaseEventListener<T> : MonoBehaviour
{
    [Header("事件监听")]
    public BaseEventSO<T> eventSO;

    [Header("事件系统(回调函数)")]
    public UnityEvent<T> reponse;

    private void OnEnable()
    {
        if (eventSO != null)
            eventSO.OnEventRaised += OnEventRasised;
    }

    private void OnDisable()
    {
        if (eventSO != null)
            eventSO.OnEventRaised -= OnEventRasised;
    }

    private void OnEventRasised(T value)
    {
        reponse.Invoke(value);
    }
}

                2.实现类

public class ObjectEventListener : BaseEventListener<int>
{
    
}

        3.事件呼叫

public class Caller : MonoBehaviour
{
    [Header("事件广播")] 
    public ObjectEventSO afterEvent;

    private void Awake() 
    {
        afterEvent.RaisEvent(30);
    }
}  
<think>首先,用户的问题是关于Unity回调函数数组的使用、定义及相关知识。用户提到参考站内引用,但指出它仅供参考,我需要基于用户的上一次问题和我的回答来构建当前响应。然而,在这个对话中,没有先前的用户消息或我的响应;这是第一个用户消息。所以,我只能基于当前查询。 用户查询的核心是:“我想了解Unity回调函数数组的相关信息 请问Unity回调函数数组的使用、定义及相关知识”。用户指定了“回调函数数组”,这似乎指的是一个数组或列表,其中包含回调函数。 从系统指令中,我需要: - 所有行内数学表达式使用 `$...$` 格式。 - 独立公式使用 `$$...$$` 并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,如 `[^1]`。 - 回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。 引用部分提到 `ReorderableList` 对象,其中包含几个回调函数,如 `drawElementCallback`、`drawHeaderCallback` 等。这看起来像是Unity Editor GUI的一部分,具体是 `UnityEditorInternal.ReorderableList`,用于在Inspector窗口中创建可重排的列表。 用户的问题是“回调函数数组”,但引用中描述的是回调函数作为委托,用于定义列表的行为。回调函数本身不是数组;数组是回调函数操作的对象或回调函数本身组成的数组。我需要澄清。 在Unity中,回调函数通常是委托(delegate),比如 `Action` 或 `UnityAction`,它们可以被赋值给事件回调。用户可能指的是如何定义一个数组或列表的回调函数,或者如何在数组元素上使用回调。 从引用看,它似乎是关于 `ReorderableList` 的,其中回调函数用于绘制和操作列表元素。所以,我应该围绕这个来解释。 结构化我的回答: 1. **定义**:解释回调函数和数组在Unity中的概念。 2. **使用**:如何定义和使用回调函数数组,特别是参考 `ReorderableList`。 3. **相关知识**:相关概念,如委托事件,以及如何在Unity中实现。 4. **代码示例**:提供一个简单的代码示例,展示如何使用。 5. **生成相关问题**:在最后添加相关问题。 确保使用中文。 添加引用标识:既然用户提供了引用,我应该在相关部分添加 `[^1]` 来引用它,但用户说引用仅供参考,所以我需要谨慎使用。 用户说:“上述引用仅供参考,并不是用户真正的需求”,所以我应该基于标准Unity知识来回答,而不是过度依赖那个引用。 在Unity中,回调函数数组可能指的是: - 一个数组,其中每个元素是一个回调函数委托)。 - 或者,在 `ReorderableList` 中,回调函数用于处理数组元素的绘制和操作。 我将假设用户指的是后者,因为引用提到了它。 回答结构: - 引言:简要介绍回调函数Unity中的概念。 - 定义:解释什么是回调函数数组(委托数组或 `ReorderableList` 的回调)。 - 使用:如何定义和使用,包括代码示例。 - 相关知识:委托类型、事件系统等。 - 生成相关问题。 对于数学表达式:可能不直接相关,但如果提到数学概念,用 `$...$`。例如,如果有公式。 代码块:用户示例中有代码块,我应该提供Unity C#代码。 最后,生成相关问题。 开始起草。 **回答大纲:** 1. **回调函数数组的定义**: - 在Unity中,回调函数通常是通过委托实现的,如 `Action` 或 `UnityAction`。 - 一个回调函数数组可以是一个委托数组,但更常见的是在UI元素如 `ReorderableList` 中使用回调来处理数组操作。 2. **在ReorderableList中的使用**: - 引用中提到 `ReorderableList`,它用于创建可重排的列表。 - 回调函数如 `drawElementCallback`、`onAddCallback` 等,定义了如何绘制和操作列表元素。 - 这些回调不是数组本身,而是用于操作一个数组(如List<T>)。 3. **代码实现**: - 提供一个简单示例,展示如何设置 `ReorderableList` 及其回调。 - 使用C#代码块。 4. **相关知识**: - 委托事件Unity中的应用。 - 如何定义自定义回调。 - 其他类似组件。 5. **相关问题**: - 生成2-3个相关问题。 添加引用:在提到 `ReorderableList` 时添加 `[^1]`。 确保语言清晰、逐步解释。 </think> ### Unity回调函数数组的使用、定义及相关知识 在Unity中,“回调函数数组”通常指的是一组委托(delegate),用于处理数组或列表的操作,特别是在编辑器扩展或UI系统中。回调函数不是数组本身,而是通过委托绑定到特定事件(如添加、删除或绘制元素),以操作一个底层数据数组(如 `List<T>`)。下面我将逐步解释定义、使用及相关知识,确保内容清晰易懂。 #### 1. **定义:什么是回调函数数组?** - **回调函数**:在Unity中,回调是一种委托类型(如 `Action` 或 `UnityAction`),它允许在特定事件发生时执行自定义逻辑。例如,当用户添加一个数组元素时,触发一个回调函数。 - **数组关联**:这里的“数组”通常指一个数据集合(如 `List<int>` 或数组 `int[]`),而回调函数数组则是一组委托,用于定义如何操作这个数据集合。常见于Unity Editor的 `ReorderableList` 类(来自 `UnityEditorInternal` 命名空间),其中多个回调函数协同工作来处理列表的绘制、添加、删除等行为。 - **关键点**:回调函数数组不是存储数据的数组,而是操作数据的“行为数组”。每个回调函数对应一个特定任务,例如: - `drawElementCallback`:绘制单个元素。 - `onAddCallback`:添加新元素时的处理。 - `onRemoveCallback`:移除元素时的处理。 - `elementHeightCallback`:定义元素高度。 - `drawHeaderCallback`:绘制列表标题。 这些回调通过委托绑定,形成一个逻辑上的“函数数组”。 #### 2. **使用:如何定义和使用回调函数数组** 在Unity中,回调函数数组主要用于编辑器扩展(如在Inspector窗口创建自定义列表)。以下是一个简单案例,展示如何定义和使用 `ReorderableList` 及其回调函数。假设我们有一个整数列表 `myList`,需要使其可重排。 **步骤:** - **创建数据数组**:定义一个数据集合(如 `List<T>`)。 - **初始化ReorderableList**:创建 `ReorderableList` 对象,并设置其回调委托。 - **实现回调函数**:为每个事件(如绘制、添加)编写逻辑。 - **绘制列表**:在 `OnGUI` 方法中调用 `DoLayoutList` 渲染列表。 代码示例(C#): ```csharp using UnityEditor; using UnityEditorInternal; using UnityEngine; using System.Collections.Generic; public class ReorderableListExample : EditorWindow { private List<int> myList = new List<int> { 1, 2, 3 }; // 数据数组 private ReorderableList reorderableList; // ReorderableList对象 [MenuItem("Window/My Reorderable List")] static void Init() { GetWindow<ReorderableListExample>().Show(); } void OnEnable() { // 初始化ReorderableList,绑定数据数组和回调函数 reorderableList = new ReorderableList(myList, typeof(int)); // 设置回调函数数组:定义每个操作的行为 reorderableList.drawElementCallback = (Rect rect, int index, bool isActive, bool isSelected) => { // 绘制单个元素:在矩形区域显示数组值 myList[index] = EditorGUI.IntField(rect, "Element " + index, myList[index]); }; reorderableList.drawHeaderCallback = (Rect rect) => { // 绘制标题 EditorGUI.LabelField(rect, "My Integer List"); }; reorderableList.elementHeightCallback = (int index) => { // 定义元素高度 return EditorGUIUtility.singleLineHeight; }; reorderableList.onAddCallback = (ReorderableList list) => { // 添加元素时的回调:向数组添加默认值 myList.Add(0); }; reorderableList.onRemoveCallback = (ReorderableList list) => { // 移除元素时的回调:删除选中元素 if (list.index >= 0) myList.RemoveAt(list.index); }; } void OnGUI() { // 绘制列表 reorderableList.DoLayoutList(); } } ``` - **如何运行**:在Unity编辑器中,通过菜单 "Window/My Reorderable List" 打开窗口。您会看到一个可重排的整数列表,支持添加、删除和拖动元素。 - **关键说明**: - 回调函数通过委托赋值(如 `reorderableList.drawElementCallback = ...`),形成一组“函数数组”。 - 这些回调操作底层数组 `myList`,实现数据UI的绑定。 - 使用 `DoLayoutList` 方法在GUI中渲染列表是必需步骤,否则列表不会显示。 #### 3. **相关知识:扩展理解** - **委托事件系统**:Unity回调基于C#委托(如 `Action` 或自定义委托)。您可以定义自己的回调数组,例如: ```csharp public Action[] callbacks = new Action[] { () => Debug.Log("Callback1"), () => Debug.Log("Callback2") }; // 调用所有回调 foreach (var callback in callbacks) callback.Invoke(); ``` 这在游戏逻辑中用于事件处理,如多个侦听器响应同一事件。 - **性能考虑**:回调函数数组在编辑器扩展中高效,但避免在每帧更新的游戏代码中使用,以防性能问题。使用委托池或缓存优化重复调用。 - **适用场景**: - 编辑器工具:创建自定义属性面板(如管理角色技能列表)。 - UI系统:在UGUI中实现动态列表(需结合 `ScrollView`)。 - 事件驱动架构:多个回调响应游戏事件(如敌人死亡触发多个效果)。 - **限制**:`ReorderableList` 仅适用于Unity Editor,不直接用于运行时游戏。在运行时,可使用 `List<T>` 结合事件Unity的 `UnityEvent` 实现类似功能。 - **数学关联**:如果回调涉及算法(如排序数组元素),回调函数可以包含数学逻辑。例如,在 `drawElementCallback` 中计算元素位置:位置 $y = \text{index} \times \text{height}$,其中 $\text{height}$ 由 `elementHeightCallback` 定义。 #### 4. **常见问题陷阱** - **空引用错误**:如果回调未正确初始化,调用时可能导致 `NullReferenceException`。始终在 `OnEnable` 中设置回调。 - **数据同步**:回调修改数组后,需手动刷新UI(如调用 `Repaint`)。 - **跨平台限制**:`ReorderableList` 是Editor-only类,不能在Android/iOS等平台使用。 通过以上解释,您应该能掌握Unity回调函数数组的核心概念。如果需要更多细节(如自定义委托类型),请参考Unity官方文档或提供具体场景。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海海不瞌睡(捏捏王子)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值