美文网首页
Unity中的全局事件系统

Unity中的全局事件系统

作者: 全新的饭 | 来源:发表于2024-01-08 17:28 被阅读0次

使用

当想要新增一个事件A时,首先需做如下2件事

  1. 在EventName类中新增一个事件名称
public partial class EventName
{
    public const string PlayerGetHit = nameof(PlayerGetHit);
}
  1. 新增一个继承EventParam的类,里面的字段是和该事件有关的数据
public class EventParamPlayerGetHit : EventParam
{
    public string PlayerName;
    public int HitValue;
}

使用
触发:EventSys.Trigger

 EventSys.Instance.Trigger(EventName.PlayerGetHit, new EventParamPlayerGetHit() { PlayerName = Name, HitValue = value });

监听:EventSys.Listen

...
EventSys.Instance.Listen(EventName.PlayerGetHit, OnPlayerGetHit);
...

private void OnPlayerGetHit(EventParam param)
{
    if (param is EventParamPlayerGetHit actualParam)
    {
        Debug.Log($"{Name} 听到 {actualParam.PlayerName} 受到 {actualParam.HitValue} 点伤害。");
    }
}

取消监听:EventSys.Unlisten

 EventSys.Instance.Unlisten(EventName.PlayerGetHit, OnPlayerGetHit);

测试

EventNamePlayerGetHit.cs:新增一个事件

public partial class EventName
{
    public const string PlayerGetHit = nameof(PlayerGetHit);
}

EventParamPlayerGetHit.cs:新增事件的对应数据

public class EventParamPlayerGetHit : EventParam
{
    public string PlayerName;
    public int HitValue;
}

Player.cs:外部调用HitPlayer方法时,触发事件(传递事件对应数据)

public class Player
{
    public readonly string Name;
    public Player(string name) { Name = name; }

    public void HitPlayer(int value)
    {
        EventSys.Instance.Trigger(EventName.PlayerGetHit, new EventParamPlayerGetHit() { PlayerName = Name, HitValue = value });
    }

    public void Destroy() { }
}

PlayerGetHitListener.cs:外部可使其开始监听、停止监听事件。监听事件期间,事件触发时,获取事件对应数据,执行相应逻辑。

using UnityEngine;

public class PlayerGetHitListener
{
    public readonly string Name;
    public PlayerGetHitListener(string name)
    {
        Name = name;
    }
    public void ListenPlayerGetHit()
    {
        Debug.Log($"{Name}尝试监听玩家受创事件。");
        EventSys.Instance.Listen(EventName.PlayerGetHit, OnPlayerGetHit);
    }
    public void UnListenPlayerGetHit()
    {
        Debug.Log($"{Name}尝试移除对玩家受创事件的监听。");
        EventSys.Instance.Unlisten(EventName.PlayerGetHit, OnPlayerGetHit);
    }
    private void OnPlayerGetHit(EventParam param)
    {
        if (param is EventParamPlayerGetHit actualParam)
        {
            Debug.Log($"{Name} 听到 {actualParam.PlayerName} 受到 {actualParam.HitValue} 点伤害。");
        }
    }

    public void Destroy()
    { }
}

EventTest.cs:通过按键测试事件的触发、监听、取消监听。

using UnityEngine;

public class EventTest : MonoBehaviour
{
    private Player _player;
    private PlayerGetHitListener _listenerA;
    private PlayerGetHitListener _listenerB;

    private void Start()
    {
        Init();
    }

    private void Update()
    {
        MyUpdate();
    }

    private void OnDestroy()
    {
        MyDestroy();
    }

    private void Init()
    {
        _player = new Player("玩家");
        _listenerA = new PlayerGetHitListener("监听者A");
        _listenerB = new PlayerGetHitListener("监听者B");
    }

    private void MyUpdate()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            _listenerA.ListenPlayerGetHit();
        }
        else if (Input.GetKeyDown(KeyCode.B))
        {
            _listenerA.UnListenPlayerGetHit();
        }
        else if (Input.GetKeyDown(KeyCode.C))
        {
            _listenerB.ListenPlayerGetHit();
        }
        else if (Input.GetKeyDown(KeyCode.D))
        {
            _listenerB.UnListenPlayerGetHit();
        }
        else if (Input.GetKeyDown(KeyCode.E))
        {
            _player.HitPlayer(UnityEngine.Random.Range(10, 100));
        }
    }

    private void MyDestroy()
    {
        _listenerB.Destroy();
        _listenerB = null;
        _listenerA.Destroy();
        _listenerA = null;
        _player.Destroy();
        _player = null;
    }
}

实现

EventName.cs:部分类,里面是所有事件名称

public partial class EventName
{
}

EventParam.cs:事件数据的基类

public abstract class EventParam
{
}

EventSys.cs:事件系统,是一个单例,提供触发、监听、取消监听事件的方法。

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

public class EventSys
{
    private static EventSys _instance;
    public static EventSys Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new EventSys();
            }
            return _instance;
        }
    }

    private Dictionary<string, List<Action<EventParam>>> _dict;
    private EventSys()
    {
        _dict = new Dictionary<string, List<Action<EventParam>>>();
    }
    public void Destroy()
    {
        _dict.Clear();
        _dict = null;
        _instance = null;
    }

    public void Listen(string eventName, Action<EventParam> action)
    {
        if (!_dict.ContainsKey(eventName))
        {
            _dict.Add(eventName, new List<Action<EventParam>>());
            Debug.Log($"新增事件:{eventName}");
        }
        if (!_dict[eventName].Contains(action))
        {
            _dict[eventName].Add(action);
        }
        else
        {
            Debug.Log($"监听事件 {eventName} 失败:重复监听!");
        }
    }
    public void Unlisten(string eventName, Action<EventParam> action)
    {
        if (_dict.ContainsKey(eventName))
        {
            if (!_dict[eventName].Remove(action))
            {
                Debug.Log($"移除监听失败,因为当前action并未监听事件 {eventName}。");
            }
            else if (_dict[eventName].Count == 0)
            {
                _dict.Remove(eventName);
            }
        }
        else
        {
            Debug.Log($"移除监听失败,因为不存在事件 {eventName}。");
        }
    }
    public void Trigger(string eventName, EventParam param)
    {
        if (_dict.ContainsKey(eventName))
        {
            foreach (var action in _dict[eventName])
            {
                action?.Invoke(param);
            }
        }
    }
}

相关文章

网友评论

      本文标题:Unity中的全局事件系统

      本文链接:https://www.haomeiwen.com/subject/nwfondtx.html