事件系统(Game Event)

框架支持带优先级和打断传播的事件系统。

如果不需要这些功能,请使用C#自带的event。

事件单例

这里写一个游戏结束事件GameStopEvent作为示例:

https://github.com/VMware233/VMFramework/blob/main/Assets/Examples/GameEvents/GameStopEvent/GameStopEvent.cs
using VMFramework.GameEvents;

namespace VMFramework.Examples
{
    // sealed class to ensure the event is singleton
    public sealed class GameStopEvent : SingletonGameEvent<GameStopEvent>
    {
        // Some GameStopEvent parameters here
        public int errorCode { get; private set; } = -1;
        
        // Set the parameters of the GameStopEvent
        public static void SetParameters(int errorCode)
        {
            instance.errorCode = errorCode;
        }

        // Triggered after the propagation of the GameStopEvent has stopped
        protected override void OnPropagationStopped()
        {
            base.OnPropagationStopped();

            // Reset the parameters of the GameStopEvent
            errorCode = -1;
        }
    }
}

给单例事件添加回调函数或者进行传播很简单:

https://github.com/VMware233/VMFramework/blob/main/Assets/Examples/GameEvents/GameStopEvent/GameStopEventDemo.cs
using UnityEngine;
using VMFramework.GameEvents;

namespace VMFramework.Examples
{
    public class GameStopEventDemo : MonoBehaviour
    {
        private void Start()
        {
            GameStopEvent.AddCallback(gameEvent =>
            {
                Debug.LogWarning($"Game has stopped with errorCode : {gameEvent.errorCode}");
                
                // If you want to stop the propagation of the event
                gameEvent.StopPropagation();
                
            }, GameEventPriority.SUPER);
            
            GameStopEvent.SetParameters(0);
            GameStopEvent.Propagate();
        }
    }
}

回调函数的优先级

在添加Callback的最后一个参数,可以指定此Callback的调用优先级,比如上面示例中的:

GameEventPriority.SUPER

用来设置此Callback的优先级。默认优先级为0,也就是GameEventPriority.TINY。

优先级越高的Callback,在事件传播时会优先调用。同一优先级的Callback,会在传播时随机调用(不保证顺序)。

常用的优先级预设如下:

https://github.com/VMware233/VMFramework/blob/main/Assets/VMFramework/Main/GameEvents/GameEvent/GameEventPriority.cs
namespace VMFramework.GameEvents
{
    public static class GameEventPriority
    {
        public const int SUPER = 0;
        public const int HIGH = 50;
        public const int MEDIUM = 100;
        public const int LOW = 150;
        public const int TINY = 200;
    }
}

中止传播

同样你也可以像上面示例中那样,在执行Callback的过程中调用StopPropagation函数来中止事件的传播。

尽量避免嵌套调用

单例事件以及下面的可配置事件是不允许在传播过程中再次传播自身的(当然传播其他事件是可以的),当尝试这样做时将会报错且此次传播无效。

当需要使用嵌套调用事件时请考虑这样设计是否合理,比如定义了一个“UI打开事件”,且打开物品栏UI时会调用打开提示框UI的,那么这样就会发生嵌套调用“UI打开事件”的情况,在这种情况下考虑将“UI打开事件”替换为“物品栏打开事件”。

如果仍然有定义“UI打开事件”的必要,那么请使用下面的 带池的事件

带池的事件

带池的事件允许在事件传播中传播自身,但是需要注意的是,带池的事件的Callback仍然是所有实例共享的,如果希望每个事件实例都有自己的Callback,那么使用下面 可配置的事件

示例:

https://github.com/VMware233/VMFramework/blob/main/Assets/Examples/GameEvents/UIOpenEvent/UIOpenEvent.cs
using VMFramework.GameEvents;

namespace VMFramework.Examples
{
    public sealed class UIOpenEvent : PooledGameEvent<UIOpenEvent>
    {
        public string uiID { get; private set; } = null;
        
        public void SetParameters(string uiID)
        {
            this.uiID = uiID;
        }

        protected override void OnPropagationStopped()
        {
            base.OnPropagationStopped();

            uiID = null;
        }
    }
}
https://github.com/VMware233/VMFramework/blob/main/Assets/Examples/GameEvents/UIOpenEvent/UIOpenEventDemo.cs
using UnityEngine;

namespace VMFramework.Examples
{
    public class UIOpenEventDemo : MonoBehaviour
    {
        private void Start()
        {
            UIOpenEvent.AddCallback(gameEvent =>
            {
                Debug.LogWarning($"UI:{gameEvent.uiID} has been opened.");
            });
            
            using var uiOpenEvent = UIOpenEvent.Get();
            uiOpenEvent.SetParameters("InventoryUI");
            uiOpenEvent.Propagate();
        }
    }
}

可配置的事件

可配置事件是基于GamePrefab->GameItem这个体系,所以自定义可配置事件需要一个事件的配置文件和事件本身。

这里写一个游戏开始事件GameStartEvent作为示例:

https://github.com/VMware233/VMFramework/blob/main/Assets/Examples/GameEvents/GameStartEvent/GameStartEvent.cs
using VMFramework.GameEvents;

namespace VMFramework.Examples
{
    public sealed class GameStartEvent : ParameterizedGameEvent<GameStartEventArguments>
    {
        
    }
}

接着是GameStartEvent的配置文件GameStartEventConfig。

https://github.com/VMware233/VMFramework/blob/main/Assets/Examples/GameEvents/GameStartEvent/GameStartEventConfig.cs
using System;
using VMFramework.GameEvents;
using VMFramework.GameLogicArchitecture;

namespace VMFramework.Examples
{
    [GamePrefabTypeAutoRegister(ID)]
    public sealed class GameStartEventConfig : GameEventConfig
    {
        public const string ID = "game_start_event";

        public override Type GameItemType => typeof(GameStartEvent);
    }
}

游戏运行流程中的OnPostInit阶段会自动依据GameStartEventConfig提供的gameItemType创建GameStartEvent。

因此无需自己再创建GameStartEvent了。

可配置事件添加回调函数和传播事件

https://github.com/VMware233/VMFramework/blob/main/Assets/Examples/GameEvents/GameStartEvent/GameStartEventDemo.cs
using System;
using System.Collections.Generic;
using UnityEngine;
using VMFramework.Core.Linq;
using VMFramework.GameEvents;
using VMFramework.Procedure;

namespace VMFramework.Examples
{
    [ManagerCreationProvider("Demo")]
    public sealed class GameStartEventDemo : ManagerBehaviour<GameStartEventDemo>
    {
        protected override void GetInitializationActions(ICollection<InitializationAction> actions)
        {
            base.GetInitializationActions(actions);
            
            actions.Add(new InitializationAction(InitializationOrder.InitComplete, OnInitComplete, this));
        }

        private void OnInitComplete(Action onDone)
        {
            // Add a callback to the GameStartEvent
            GameEventManager.AddCallback(GameStartEventConfig.ID, (GameStartEventArguments arguments) =>
            {
                Debug.LogWarning($"Game Started with {arguments.playerCount} players");
            }, GameEventPriority.SUPER);
            
            // Propagate the GameStartEvent
            GameEventManager.Propagate(GameStartEventConfig.ID, new GameStartEventArguments(2));
            
            onDone();
        }
    }
}

上面示例简单演示了给事件添加委托(或者说回调函数Callback),以及如何传播事件(也就是调用这些Callback)。

在通过GameEventManager添加Callback或传播事件时需要保证在GameEventManager初始化之后,见游戏运行流程

最后更新于

这有帮助吗?