07. 泛型事件框架

事件监听和发布

我们要实现这样一个功能,当玩家在 Map 场景中点击一个图标的时候,需要发送事件给场景管理器,场景管理器监听事件,然后执行切换场景的操作

在勇士传说中,我们使用 ScriptableObject.UnityAction 发布事件,以及监听事件,那时候每种类型都有一个 ScriptableObject,非常繁琐。所以我们这次使用了泛型来简化代码编写

编写代码

目录结构

在 Scripts/Events 目录下,创建 Editor(用于扩展 Inspector 窗口)、MonoBehaviour(用于事件监听)、ScriptableObject(用于事件发布)

在 Game Data 目录下,创建 Events(用于创建事件)

ScriptableObject

首先,我们需要定义一个 BaseEventSO,代码如下

在 BaseEventSO 里面,定义了一个 UnityAction,用于事件发布和订阅。当发布者调用 RaiseEvent 的时候,就会通知订阅者,同时记下当前的发布者

然后需要定义一个 ObjectEventSO,用于传递 object 类型的事件

MonoBehaviour

和 ScriptableObject 一样,我们需要定义 BaseEventListener,用于监听事件。它的写法和勇士传说里很多监听者的写法一样,在OnEnable的时候注册事件监听,在OnDisable的时候注销事件监听,在事件产生的时候调用 UnityEvent 的 Invoke

同样我们也写一个监听 object 事件的类

Events

因为我们已经创建好 ObjectEventSO 了,所以我们可以创建一个 Event 出来,名字叫做LoadRoomEvent

在 RoomPrefab 里发布 LoadRoomEvent

在 SceneLoadManager 里面监听 LoadRoomEvent

当 RoomPrefab 发布事件的时候,SceneLoadManager 就能监听到这个事件,然后调用OnLoadRoomEvent方法

扩展 Inspector

如上图所示,当我们查看 LoadRoomEvent 的时候,可以看到消息的发布者,以及消息的订阅者。这是怎么实现的呢?

消息的发布者,其实在 ScriptableObject/BaseEventSO 里面已经实现了

消息的订阅者,代码比较复杂,我贴出来,大家看看就好

BaseEventSOEditor

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(BaseEventSO<>))]
public class BaseEventSOEditor<T> : Editor
{
    private BaseEventSO<T> baseEventSO;

    private void OnEnable() {
        if (baseEventSO == null)
        {
            baseEventSO = target as BaseEventSO<T>;
        }
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        EditorGUILayout.LabelField($"订阅数量: {GetListeners().Count}");

        foreach (var listener in GetListeners())
        {
            EditorGUILayout.LabelField(listener.ToString());
        }
    }

    private List<MonoBehaviour> GetListeners()
    {
        List<MonoBehaviour> listeners = new List<MonoBehaviour>();

        if (baseEventSO == null || baseEventSO.OnEventRaised == null)
        {
            return listeners;
        }

        var subscribers = baseEventSO.OnEventRaised.GetInvocationList();
        foreach (var subscriber in subscribers)
        {
            var obj = subscriber.Target as MonoBehaviour;
            if (!listeners.Contains(obj))
            {
                listeners.Add(obj);
            }
        }

        return listeners;
    }
}

ObjectEventSOEditor

项目相关代码

代码仓库:https://gitee.com/nbda1121440/DreamOfTheKingdom.git

标签:20240302_1225

posted @ 2024-03-02 23:19  hellozjf  阅读(113)  评论(0编辑  收藏  举报