Chaoli

Unity全局事件系统

Unity全局事件系统的几种实现

Unity开发中,常用到一些与游戏进度有关的广播事件(例如:游戏开始时启用敌人生成器、启用玩家控制……),此时利用全局事件可以提升便利性。全局事件系统的实现方式在实践中遇到过多种,列举如下:

基于字典

public enum Event
{
    // 参数int: 玩家ID
    UserLogin = 1,
    
    // ...
}

public static class EventSystem
{
    private static Dictionary<Event, Action<object>> _eventListeners = new();
    
    
    public static void AddListener(Event eventType, Action<object> listener)
    {
        if (_eventListeners.ContainsKey(eventType))
        {
            _eventListeners[eventType] += listener;
        }
        else
        {
            _eventListeners.Add(eventType, listener);
        }
    }

    public static void RemoveListener(Event eventType, Action<object> listener)
    {
        _eventListeners[eventType] -= listener;
    }
    
    public static void InvokeEvent(Event eventType, object parameter)
    {
        if (_eventListeners[eventType].TryGetValue(eventType, out Action<object> listener))
        {
            listener?.Invoke(parameter);
        }
    }
}

基于全局event变量

static class EventManager
{
    public static event Action<int> UserLogin;
    public static event Action<Args> EventRaised;
    // ...
}

基于Scriptable Object

当前采用的方案。对于不同类事件分到不同信道,每个信道可作为Scriptable Object创建。

public abstract class EventChannel<TEventArgs> : ScriptableObject
{
    public event Action<TEventArgs> Raised;

    
    public void Raise(TEventArgs eventArgs)
    {
        Raised?.Invoke(eventArgs);
    }
}

[CreateAssetMenu(fileName = "New Login Event", menuName = "Events/Login Event")]
public class LoginEventChannel : EventChannel<LoginEventChannel.Args>
{
    public struct Args
    {
        public int UserId;
    }
}

使用方法:

public class UI : MonoBehaviour
{
    [SerializeField] private LoginEventChannel loginEvent;
    
    
    private void Start()
    {
        loginEvent.Raised += LoginEvent_Raised;
	}
    
    private void OnDestroy()
    {
        loginEvent.Raised -= LoginEvent_Raised;
    }
    
    private void LoginEvent_Raised(LoginEventChannel.Args args)
    {
        Debug.Log($"User ID: {args.UserId}");
    }
}