EventCore 事件模块

文章目录

EventCore 事件模块

特点

  • EventCore 是一个简单,易于使用的 Unity 事件管理方案
  • EventCore 基于 QFramework 的事件管理思路,独立演化而成
  • EventCore 能够自动进行注销事件操作,降低开发者的考虑角度
  • EventCore 仅需输入一次字符串,之后操作可以使用 IDE 自动代码补全
  • EventCore 可以快速监测关键数据的变化,触发事件

构建思路

  • 核心类对象 EventBlock
    • 整个事件系统的核心数据结构,作为流通在事件系统中的最小单元
  • 定制类对象 BindableProperty
    • 基于 EventBlock 的封装数据结构,用于监测基础数据变化的类,比如 int,float,string

文件结构

  • EventCore
    • Editor
    • Example
    • Prefab
    • Scripts

快速使用,存在 ZFramework 架构的情况下

  • 创建任意脚本,类名为 EventCoreUseTest,修改 MonoZFController 使用 ZFramework 表现层接口(继承 Mono 不影响正常使用 EventCoreZFController 也继承 Mono
  • 声明一个 EventBlock 变量,并在声明时初始化(推荐在此处直接初始化),原则上只要在注册任何方法之前进行名称赋值即可,EventBlock<T> 最多可以接受四个参数,代表有参数的委托模块。
  • 然后在 Mono 的生命周期中,执行方法的注册,可以直接使用 Lambda 表达式
  • 然后再使用 AutoUnsubscribeWhenGameObjectDestroyed(this) 方法,表示在传入的物体上挂载一个自动注销的方法,这个表示物体销毁时自动注销,避免造成空引用
  • 另外还有AutoUnsubscribeWhenGameObjectOnDisable(gameObject) 方法,表示物体隐藏时自动注销,*该方法为仅作用一次 * 如果重新显示,需要重新注册新的方法
  • 甚至可以传入其他物体,将该脚本的自动注销与其他物体关联。参数可以是 MonoGameObject
  • AwakeStart 中都注册一个方法。
  • 把这个脚本挂载到对应的物体上,启动 Unity ,按键 Y ,发送事件
  • 声明 -> 注册 -> 订阅自动注销 -> 触发事件,整个流程已经完成
  • 以下部分为演示

脚本演示

using System;  
using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;  
using ZFramework.CoreComponent.EventCore;  
using ZFramework.Example;  
using ZFramework.Framework;  
  
// 继承 ZFController 类,并实现 GetArchitectureInterface 抽象方法  
public class EventCoreUseTest : ZFController  
{  
    protected override IArchitecture GetArchitectureInterface()  
    {  
        // 返回自定义的 Architecture 架构类,没有继承 ZFController 则忽略  
        return PointGame.Interface;  
    }  
  
    // 创建一个 EventBlock 变量,可以简单理解为委托的封装  
    // 必须初始化调用 InitPrefixName(nameof(TestUse));    
    // 其中 nameof(TestUse) 表示委托的名称,用于在 EventCore 中查找
    // (可以自定义任何字符串,但必须唯一,所以推荐直接使用 nameof(TestUse))
    public EventBlock TestUse = new EventBlock().InitPrefixName(nameof(TestUse));  
  
    void Awake()  
    {  
        // 注册一个委托,当 TestUse 事件触发时,会调用这个委托  
        // 注意:AutoUnsubscribeWhenGameObjectDestroyed 表示当 GameObject 销毁时,自动取消注册  
        TestUse.Register(() =>  
        {  
            Debug.Log("测试 Awake ");  
        }).AutoUnsubscribeWhenGameObjectDestroyed(this);  
    }  
  
    void Start()  
    {  
        // 注册一个委托,当 TestUse 事件触发时,会调用这个委托  
        // 注意:AutoUnsubscribeWhenGameObjectOnDisable 表示当 GameObject 禁用时,自动取消注册  
        // 其中 gameObject 表示取消注册的 GameObject        
        TestUse.Register(() =>  
        {  
            Debug.Log("测试 Start 注册");  
        }).AutoUnsubscribeWhenGameObjectOnDisable(gameObject);  
    }  
  
    void Update()  
    {  
        if (Input.GetKeyDown(KeyCode.Y))  
        {  
            // 发送事件  
            TestUse.SendEvent();  
              
            // 原则上不在表现层触发事件  
            // 因为事件是架构层统一管理,表现层只需要注册事件即可  
            // 当然,如果确实需要,也可以在表现层触发事件  
        }  
    }  
}

截图演示

EventCore快速使用演示图

截图解析
  • 左边包含了架构的层级(调用了架构核心就会自动生成),可以找到 EventCore 查看全局委托模块信息
  • 右边则是 EventCoreUseTest 的面板信息,可以发现 TestUse 已经序列化,可以查看委托模块的名称,以及当前一共订阅了多少个方法
  • 物体还挂载了两个注销委托的触发器 Trigger 脚本,开发者不用理会,无感自动注销
  • 输出了两个日志,表示 AwakeStart 中注册均可,推荐在 Start

使用规则

  • 只能使用委托块注册事件,仅提供这个方法,从编写阶段杜绝同名的可能
  • 可以使用字符串名称和委托块发送事件
  • 委托块的订阅数为 0 时会自动销毁对象,释放内存
  • 在注册阶段选择是否需要进行自动注销
  • 一个委托块不要同时存在手动注销和自动注销,如果不选择自动注销,则需要自定义注销时机

使用技巧推荐

全局事件中心

  • 创建一个静态类,用来存放所有的 EventBlock
  • 声明静态的 EventBlock 变量
  • 所有变量声明在一个类中,且默认使用变量名转化为字符串,作为 EventBlock 的名称
  • 从编写代码层面直接解决了可能不唯一的问题,因为不可存在同名的变量
using Sirenix.OdinInspector;  
using UnityEngine;  
using ZFramework.CoreComponent.EventCore;  
using ZFramework.Framework;  
  
namespace ZFramework.Example  
{  
    public static class PointGameEventView  
    {  
        public static EventBlock CompleteClick = new EventBlock().InitPrefixName(nameof(CompleteClick));  
        public static EventBlock Example = new EventBlock().InitPrefixName(nameof(Example)); 
        // Int 参数的委托模块  
		public static EventBlock<int> ExampleInt = new EventBlock<int>().InitPrefixName(nameof(ExampleInt));
		// Int 和 String 两个参数的委托模块  
		public static EventBlock<int,string> ExampleIntString = new EventBlock<int,string>().InitPrefixName(nameof(ExampleIntString));
		// ...
    }  
}
  • 静态类外界调用也较为方便
using Sirenix.OdinInspector;  
using UnityEngine;  
using ZFramework.CoreComponent.EventCore;  
using ZFramework.Framework;  
  
namespace ZFramework.Example  
{  
    public class Test  
    {  
	    void Start()  
	    {  
	        // 调用 CompleteClick
	        PointGameEventView.CompleteClick.Register(() =>  
	        {  
	            Debug.Log("测试 Start 注册");  
		    }).AutoUnsubscribeWhenGameObjectOnDisable(gameObject);  
	    }  
       
    }  
}


只读静态变量,避免后期误赋值

// 声明 EventBlock 
public static readonly EventBlock PressedA = new EventBlock().InitPrefixName(nameof(PressA));  
  
void Start()  
{    
	// 注册事件,只能使用委托模块注册    
    
	// 无参数委托模块
	PressA.Register(EventCoreDebug);    
    EventCore.Register(PressedA, EventCoreDebug);    
    EventCore.Register(PressedA, () =>    
    {    
        Debug.LogFormat("这是一个 Lambda 表达式方法的订阅调用");    
	});  
}  
  
void Update()  
{  
    //需要时进行触发  
    if (Input.GetKeyDown(KeyCode.A))    
	{    
		// 直接使用 委托模块调用
		PressA.SendEvent();
		// 直接持有 EventBlock 调用    
	    EventCore.SendEvent(PressedA);    
		// 使用 字符串 调用,直接输入 字符串 需要前缀    
        EventCore.SendEvent(PressedA.GetName());    
    }  
}  

BindableProperty 特殊委托模块 用于监测数据的变化

  • 基于 EventBlock<T> 的封装,T 为泛型,可以使用任何 能够直接比较 的类 where T : IEquatable<T>
  • 当监测数据的值发生改变时,自动触发事件,主要用于数据层的发送事件
简单示例
  • 在注册时选择是否要立刻触发一次,以及是否要自动注销
// 声明 BindableProperty 并进行初始化 
// 设置初始值和设置 EventBlock 字符串名称,仅需设置一次  
public readonly BindableProperty<int> Number =    
    new BindableProperty<int>()    
        .InitValue(0)    
        .InitEventName(nameof(Number)); 
// 或者使用 InitProperty(nameof(Number), 0); 第二个参数有默认值设置
public readonly BindableProperty<int> Number =  
    new BindableProperty<int>().InitProperty(nameof(Number), 0);
  
void Start()  
{  
    // 注册方法完当前方法后,立刻触发一次,JustTriggerOnce  
    // 对象销毁时自动注销 
    Number.Register(num =>  
      {  
          Debug.LogFormat("当前 Number 数据的值为: {0} ", num);  
      })  
      .JustTriggerOnce(Number.Value)
      .AutoUnsubscribeWhenGameObjectDestroyed(gameObject);
    // 也可以直接使用 RegisterJustTriggerOnce
    Number.RegisterJustTriggerOnce(num =>  
      {  
          CountText.text = $"当前 Number 数据的值为: {Number.Value} ";  
          Debug.LogFormat(" 使用 JustTriggerOnce 立刻触发一次委托模块,当前值为: {0} ", num);  
      })  
      .AutoUnsubscribeWhenGameObjectDestroyed(gameObject);
}  

Example 示例场景

  • 可以在 Example 文件夹中查看更加完整的示例

API 详细文档

EventCore

public static UnsubscribeRecord Register(EventBlock eventBlock, Action action)
  • 注册委托模块
  • 拥有多个重载,分别对应不同的 EventBlock 事件块
// Register 拥有多个重载,均使用相同方法编写
// 只提供了委托模块的注册,这样可以在编写过程中避免重名
EventCore.Register(EventBlock eventBlock, Action action);  
public static void UnRegister(string eventBlockName, Action action)
  • 注销委托模块中的单个订阅方法(直接使用字符串必须有前缀
  • 拥有多个重载,分别对应不同的 EventBlock 事件块
// 两种注销方式,字符串 或者 EventBlock  
// 委托模块名书写方式: 
//(前缀)EventHub.ZeroParamPrefix +(临时未赋值变量的模块名) "TempEventBlock" 
// 或 (全局模块)GlobalEventBlock.GetName()  
EventCore.UnRegister(string eventBlockName, Action action);  
EventCore.UnRegister(EventBlock eventBlock, Action action);  
public static void UnRegister(EventBlock eventBlock, Action action)
  • 注销委托模块中的单个订阅方法(直接使用字符串必须有前缀
  • 拥有多个重载,分别对应不同的 EventBlock 事件块
// 两种注销方式,字符串 或者 EventBlock  
// 委托模块名书写方式: 
//(前缀)EventHub.ZeroParamPrefix +(临时未赋值变量的模块名) "TempEventBlock" 
// 或 (全局模块)GlobalEventBlock.GetName()  
EventCore.UnRegister(string eventBlockName, Action action);  
EventCore.UnRegister(EventBlock eventBlock, Action action);  
public static void SendEvent(string eventBlockName)
  • 触发委托模块(直接使用字符串必须有前缀
  • 拥有多个重载,分别对应不同的 EventBlock 事件块
// 两种触发方式,字符串 或者 EventBlock  
// 委托模块名书写方式: 
//(前缀)EventHub.ZeroParamPrefix +(临时未赋值变量的模块名) "TempEventBlock" 
// 或 (全局模块)GlobalEventBlock.GetName()  
EventCore.SendEvent(string eventBlockName, Action action);  
EventCore.SendEvent(EventBlock eventBlock, Action action);  
public static void UnRegisterEventBlock<T>(T baseEventBlock)
  • 直接注销 EventBlock 实例的所有方法
// 两种注销委托模块方式,字符串 或者 EventBlock  
// 委托模块名书写方式: 
//(前缀)EventHub.ZeroParamPrefix +(临时未赋值变量的模块名) "TempEventBlock" 
// 或 (全局模块)GlobalEventBlock.GetName()  
EventCore.UnRegisterEventBlock(string eventBlockName, Action action);  
EventCore.UnRegisterEventBlock(EventBlock eventBlock, Action action);  
public static void UnRegisterEventBlock(string eventBlockName)
  • 直接注销 EventBlock 实例的所有方法
// 两种注销委托模块方式,字符串 或者 EventBlock  
// 委托模块名书写方式: 
//(前缀)EventHub.ZeroParamPrefix +(临时未赋值变量的模块名) "TempEventBlock" 
// 或 (全局模块)GlobalEventBlock.GetName()  
EventCore.UnRegisterEventBlock(string eventBlockName, Action action);  
EventCore.UnRegisterEventBlock(EventBlock eventBlock, Action action);  
public static Transform EnsureEventCore()
  • 架构内部用于初始化 EventCore 的方法
public static bool QueryDictionaryIsHas(string eventBlockName)
  • 特殊调试情况用于查询全局事件字典中是否包含这个委托块

EventBlock

  • EventBlock 预设最多4个参数的方法
  • 声明时设置 EventBlock 名称字符串
public string GetName()
  • 获取 EventBlock 的字符串名称
var blockName = PressedA.GetName();
public int GetActionCount()
  • 获取 EventBlock 的订阅方法数量
var count = PressedA.GetActionCount();
public EventBlock InitPrefixName(string name)
  • 初始化名称,会自动附加前缀
  • 针对不同的 EventBlock 方法名相同
public EventBlock PressedA = new EventBlock().InitPrefixName(nameof(PressedA));
public UnsubscribeRecord Register(Action action)
  • EventBlock 的直接注册方法
  • 针对不同的 EventBlock 方法名相同
PressedS.Register(EventCoreDebugOneParam);
public void UnRegister(Action action)
  • EventBlock 注销单个方法的订阅
  • 针对不同的 EventBlock 方法名相同
PressedA.UnRegister(EventCoreDebug);
public void UnRegisterEventBlockSelf()
  • EventBlock 快速注销自身块的所有方法订阅
  • 针对不同的 EventBlock 方法名相同
PressedS.UnRegisterEventBlockSelf();
public void SendEvent()
  • EventBlock 的事件触发
  • 针对不同的 EventBlock 方法名相同
PressedA.SendEvent();

BindableProperty 监测数据机制

  • BindableProperty<T> : IBindableProperty<T> where T : IEquatable<T>
  • 基于 EventBlock<T> 的封装,T 为泛型,可以使用任何 能够直接比较 的类 where T : IEquatable<T>
public EventBlock<T> GetEventBlock()
  • 获取 BindableProperty 中的 EventBlock
// 获取 BindableProperty 中的 EventBlock<T> 返回一个 EventBlock<T> 
var block = Number.GetEventBlock();
public string ToStringValue()
  • 输出值的字符串类型
// 输出值的字符串类型
var str = Number.ToStringValue();
public BindableProperty<T> InitProperty(string eventBlockName, T initialValue = default)
  • 初始化 Number 数据,使用初始化方法,会使用 Int 的默认值作为初始值
/// <summary>  
/// 初始化 Number 数据,使用初始化方法,会使用 Int 的默认值作为初始值  
/// </summary>  
public readonly BindableProperty<int> Number =  
    new BindableProperty<int>().InitProperty(nameof(Number));
public BindableProperty<T> InitValue(T initialValue)
/// <summary>  
/// 初始化 Count 数据,使用链式方法  
/// </summary>  
public readonly BindableProperty<int> Count =  
    new BindableProperty<int>()  
        .InitValue(10)  
        .InitEventName("Count");
public BindableProperty<T> InitEventName(string eventBlockName)
/// <summary>  
/// 初始化 Count 数据,使用链式方法  
/// </summary>  
public readonly BindableProperty<int> Count =  
    new BindableProperty<int>()  
        .InitValue(10)  
        .InitEventName("Count");
public void SetValueWithoutEvent(T newValue)
// 特殊情况下的值修改,不触发事件,一般不使用  
Number.SetValueWithoutEvent(10);  
// 通常情况下的值修改,会触发事件  
Number.Value = 20;
public UnsubscribeRecord<T> Register(Action<T> onValueChanged)
// 委托块注册方法
Number.Register(num =>  
      {  
          Debug.LogFormat("当前 Number 数据的值为: {0} ", num);  
      })  
      .JustTriggerOnce(Number.Value)  
      .AutoUnsubscribeWhenGameObjectDestroyed(gameObject);
public void UnRegister(Action<T> actionOne)
// 以下仅为演示,自动注销和手动注销不要同时出现  
// 直接使用 EventBlock 模块实例注销单个方法的订阅,此函数有多个重载  
// EventHub.UnRegister(PressedA, EventCoreDebug);  
PressedA.UnRegister(EventCoreDebug);
public IUnsubscribeRecord RegisterJustTriggerOnce(Action<T> actionOne)
// 特殊的注册方法,会立刻触发一次事件,通常用于初始化刷新 UI
Count.RegisterJustTriggerOnce(num =>  
     {  
         CountText.text = $"当前 Count 数据的值为: {Count.Value} ";  
         Debug.LogFormat(" 使用 JustTriggerOnce 立刻触发一次委托模块,当前值为: {0} ", num);  
     })  
     .AutoUnsubscribeWhenGameObjectDestroyed(gameObject);

AutoUnsubscribeOnDestroyTrigger 自动注销机制

  • 在注册的时候选择是否要自动注销,使用链式方法
// 当物体销毁时自动注销,避免空引用  
IUnsubscribeRecord.AutoUnsubscribeWhenGameObjectDestroyed(UnityEngine.GameObject gameObject);  
IUnsubscribeRecord.AutoUnsubscribeWhenGameObjectDestroyed(MonoBehaviour mono);
PressedF.Register(EventCoreDebugThreeParam).AutoUnsubscribeWhenGameObjectDestroyed(gameObject);
// 当物体隐藏时注销,仅触发一次,重新激活后需要再次使用  
IUnsubscribeRecord.AutoUnsubscribeWhenGameObjectOnDisable(UnityEngine.GameObject gameObject); 
IUnsubscribeRecord.AutoUnsubscribeWhenGameObjectOnDisable(MonoBehaviour mono);
PressedD.Register(EventCoreDebugTwoParam).AutoUnsubscribeWhenGameObjectOnDisable(gameObject);

说明和扩展

简要提醒

  • 有部分公开方法为 EventCore 内部搭建使用,可以不用理会
  • 已经通过接口隔离限制部分方法,遵循直接给出的方法使用规则即可正常运转 EventCore 系统

参数限制

  • 通常 4 个参数可以满足绝大部分需求
  • 如有需要可以自定义扩展更多参数的委托模块

扩展步骤

  1. 根据 AbstractEventBlock<T> 的模板创建一个抽象类,继承 IBaseEventBlock
  2. 补充声明 UnityAction<T> mCachedAction 缓存 Action 和 UnityAction<T> mEventAction事件 Action,以及T mData 根据需要的参数数量进行补充说明
  3. 根据 EventBlock<T> 创建一个实现类,补充完善 InitPrefixName(string name)并返回EventBlock<T>根据需要的参数数量进行补充
  4. 在 EventCore 中新增参数前缀常量 EventCore.TwoParamPrefix 即可正常使用
  • 26
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值