当前位置: 首页 > news >正文

【Unity】高性能的事件分发系统

1. 脚本代码完整介绍

(1) EventDef.cs

功能
  • 定义事件名称常量,作为全局事件标识符。
  • 示例中定义了 EVENT_GENERATE_CHESS (生成棋子事件)。
代码
using UnityEngine;public class EventDef : MonoBehaviour
{/// <summary>/// 生成棋子/// </summary>public const string EVENT_GENERATE_CHESS = "EVENT_GENERATE_CHESS";
}
特点
  • 简单清晰,仅用于集中管理事件名称。
  • 通过 const 确保事件名称不可修改。

(2) EventHandlerPool.cs

功能
  • 管理事件处理器的对象池,优化高频事件的性能。
  • 支持懒加载、预加载和资源回收。
代码
using System.Collections.Generic;public class EventHandlerPool
{private Dictionary<string, Stack<GameplayEventHandler>> pools = new Dictionary<string, Stack<GameplayEventHandler>>();public GameplayEventHandler GetHandler(string eventName, GameplayEventHandler originalHandler){if (!pools.ContainsKey(eventName)){pools.Add(eventName, new Stack<GameplayEventHandler>());PreloadPool(eventName, 10, originalHandler);}var pool = pools[eventName];return pool.Count > 0 ? pool.Pop() : originalHandler;}// 预加载独立对象池private void PreloadPool(string eventName, int count, GameplayEventHandler handler){var pool = pools[eventName];for (int i = 0; i < count; i++)pool.Push(handler);}public void ReturnHandler(string eventName, GameplayEventHandler handler){if (pools.ContainsKey(eventName))pools[eventName].Push(handler);}public void ClearPool(string eventName){if (pools.ContainsKey(eventName))pools[eventName].Clear();}public void ClearAll(){pools.Clear();}
}
特点
  • 懒加载:首次调用 GetHandler 时初始化对象池。
  • 预加载:通过 PreloadPool 提前分配处理器实例。

(3) EventDispatcher.cs

功能
  • 核心事件分发系统,支持订阅、发布、注销事件。
  • 集成对象池优化,提供单例访问。
代码
using System.Collections.Generic;
using UnityEngine;public delegate void GameplayEventHandler(params object[] args);
public interface IGameplayObserver
{void OnEventTriggered(string eventName, params object[] args);
}
public class EventDispatcher
{// 存储事件与独立对象池的映射private EventHandlerPool eventPools = new EventHandlerPool();private Dictionary<string, Dictionary<int, GameplayEventHandler>> listeners = new Dictionary<string, Dictionary<int, GameplayEventHandler>>();private readonly string szErrorMessage = "DispatchEvent Error, Event:{0}, Error:{1}, {2}";private static EventDispatcher s_instance;public static EventDispatcher instance{get{if (null == s_instance)s_instance = new EventDispatcher();return s_instance;}}// 订阅事件接口观察者模式public void Regist(string eventName, IGameplayObserver observer){if (observer == null) return;Regist(eventName, (args) => observer.OnEventTriggered(eventName, args));}/// <summary>/// 订阅事件/// </summary>/// <param name="eventName">事件名</param>/// <param name="gameplayEventHandler">事件</param>public void Regist(string eventName, GameplayEventHandler gameplayEventHandler){if (gameplayEventHandler == null) return;if (!listeners.ContainsKey(eventName))listeners.Add(eventName, new Dictionary<int, GameplayEventHandler>());var handlerDic = listeners[eventName];var handlerHash = gameplayEventHandler.GetHashCode();if (handlerDic.ContainsKey(handlerHash))handlerDic.Remove(handlerHash);listeners[eventName].Add(gameplayEventHandler.GetHashCode(), gameplayEventHandler);}/// <summary>/// 订阅事件(独立对象池)/// </summary>/// <param name="eventName"></param>/// <param name="gameplayEventHandler"></param>public void RegistWithPool(string eventName, GameplayEventHandler gameplayEventHandler){if (gameplayEventHandler == null) return;var pooledHandler = eventPools.GetHandler(eventName, gameplayEventHandler);Regist(eventName, pooledHandler);}/// <summary>/// 注销事件/// </summary>/// <param name="eventName">事件名</param>/// <param name="gameplayEventHandler">事件</param>public void UnRegist(string eventName, GameplayEventHandler gameplayEventHandler){if (null == gameplayEventHandler) return;if (listeners.ContainsKey(eventName)){listeners[eventName].Remove(gameplayEventHandler.GetHashCode());if (null == listeners[eventName] || 0 == listeners[eventName].Count){listeners.Remove(eventName);}}}/// <summary>/// 注销事件(归还对象池)/// </summary>public void UnRegistWithPool(string eventName, GameplayEventHandler gameplayEventHandler){if (gameplayEventHandler == null) return;if (listeners.TryGetValue(eventName, out var handlerDic) &&handlerDic.TryGetValue(gameplayEventHandler.GetHashCode(), out var handler)){handlerDic.Remove(gameplayEventHandler.GetHashCode());eventPools.ReturnHandler(eventName, handler); // 归还对象池if (handlerDic.Count == 0){listeners.Remove(eventName);}}}/// <summary>/// 发布事件(合并方法)/// </summary>/// <param name="eventName">事件名</param>/// <param name="usePool">是否使用对象池</param>/// <param name="objects">事件参数</param>public void DispatchEvent(string eventName, bool usePool = false, params object[] objects){Dictionary<int, GameplayEventHandler> handlerDic;// 获取事件处理器字典if (usePool){if (!listeners.TryGetValue(eventName, out handlerDic) || handlerDic == null || handlerDic.Count == 0)return;}else{if (!listeners.ContainsKey(eventName) || listeners[eventName] == null || listeners[eventName].Count == 0)return;handlerDic = listeners[eventName];}// 复制一份避免遍历时修改var dic = new Dictionary<int, GameplayEventHandler>(handlerDic);foreach (var handler in dic.Values){try{handler(objects);}catch (System.Exception ex){Debug.LogErrorFormat(szErrorMessage, eventName, ex.Message, ex.StackTrace);}}}/// <summary>/// 清空事件/// </summary>/// <param name="eventName">事件名</param>public void ClearEvents(string eventName){if (listeners.ContainsKey(eventName)){listeners.Remove(eventName);}}// 清空特定事件的对象池public void ClearEventPool(string eventName){eventPools.ClearPool(eventName);}/// <summary>/// 清空所有事件和对象池/// </summary>public void ClearAll(){listeners.Clear();eventPools.ClearAll();}
}
特点
  • 单例模式:全局唯一实例。
  • 多订阅方式:支持委托和接口订阅。
  • 对象池集成:通过 RegistWithPool 和 UnRegistWithPool 管理资源。
  • 异常处理:捕获事件处理中的异常并记录日志。

2. 系统使用的编程模式分析

(1) 观察者模式(Observer Pattern)

  • 核心思想:定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象自动收到通知。
  • 实现方式
    • IGameplayObserver 接口定义了观察者的统一行为。
    • EventDispatcher 维护订阅列表,通过 DispatchEvent 通知所有观察者。

(2) 单例模式(Singleton Pattern)

  • 核心思想:确保一个类只有一个实例,并提供全局访问点。
  • 实现方式
    • EventDispatcher 通过静态 instance 属性提供单例访问。

(3) 对象池模式(Object Pool Pattern)

  • 核心思想:通过复用对象减少资源分配和垃圾回收开销。
  • 实现方式
    • EventHandlerPool 管理 GameplayEventHandler 的栈式对象池。
    • 预加载和懒加载结合,平衡性能和内存。

3. 系统优势与适用场景

优势

  1. 高性能:对象池减少GC压力,适合高频事件(如游戏中的伤害计算)。
  2. 解耦:观察者模式分离事件发布者和订阅者。
  3. 灵活性:支持委托和接口两种订阅方式。
  4. 可维护性:集中管理事件名称和分发逻辑。

适用场景

  • 游戏开发(技能触发、UI交互)。
  • 实时系统(如物联网设备状态通知)。
  • 需要解耦的模块间通信。

总结

当前系统通过 观察者模式 和 对象池模式 实现了高性能的事件分发,结合 单例模式 提供全局访问点,并通过 发布-订阅模式 解耦模块。适用于需要高效、灵活事件处理的场景,如游戏开发和实时交互系统。


文章转载自:

http://2aXjQ3vU.nnwpz.cn
http://F1pAytkC.nnwpz.cn
http://31YhFiC4.nnwpz.cn
http://CJgbLtPI.nnwpz.cn
http://F3pPq2uh.nnwpz.cn
http://kiEoOs3K.nnwpz.cn
http://kHIef78K.nnwpz.cn
http://ro2Ij1ZW.nnwpz.cn
http://gHGzNJXn.nnwpz.cn
http://EODXrFDt.nnwpz.cn
http://cW42cWPh.nnwpz.cn
http://UlV67Ihb.nnwpz.cn
http://42ytiSks.nnwpz.cn
http://e7prMCaT.nnwpz.cn
http://4ittVh8C.nnwpz.cn
http://Ph7rsmy2.nnwpz.cn
http://mNi8pYO7.nnwpz.cn
http://iJzszLKR.nnwpz.cn
http://Lxyyg691.nnwpz.cn
http://NLgTqtVb.nnwpz.cn
http://ELYQKcNl.nnwpz.cn
http://DzmbXOyb.nnwpz.cn
http://ooAu0hRu.nnwpz.cn
http://5suRv4r0.nnwpz.cn
http://NfLyFkpg.nnwpz.cn
http://ZyUAcdJu.nnwpz.cn
http://BMfyTJ2U.nnwpz.cn
http://01X2n2fu.nnwpz.cn
http://xda2jSoQ.nnwpz.cn
http://YGC0HLWI.nnwpz.cn
http://www.dtcms.com/a/384450.html

相关文章:

  • BM3D 图像降噪快速算法的 MATLAB 实现
  • 【pycharm】 ubuntu24.04 搭建uv环境
  • 科普:Python 的包管理工具:uv 与 pip
  • Golang语言入门篇002_安装Golang
  • cemu运行塞尔达传说:旷野之息的闪退问题以及解决方案记录
  • 【面试之Redis篇】主从复制原理
  • MySQL 8.0 在 Ubuntu 22.04 中如何将启用方式改为mysql_native_password(密码认证)
  • 轨道交通绝缘监测—轨道交通安全的隐形防线
  • Golang 语言中的函数类型
  • 《投资-54》数字资产的形式有哪些?
  • leetcode41(对称二叉树)
  • 链表详解:(后续会更新)
  • 光谱相机在半导体缺陷检测中的应用
  • 计算机组成原理-第一章
  • 修改 Windows 10 系统更新暂停天数指南
  • Flutter系统亮度检测完全指南:MediaQuery.platformBrightnessOf() 的妙用
  • flutter鸿蒙:适配app_links插件
  • 计算机视觉(opencv)实战二十二——指纹图像中提取特征点,计算两两指纹之间的相似度
  • 如何启动档案开启对话框及浏览资料夹对话框
  • 抗菌涂层与智能诊疗:伟荣医疗重构口腔器械感控与精准治疗新范式
  • python3
  • 茉莉 X4-QZ 840M矿机参数分析:Etchash算法挖矿的高效能选择
  • iOS App 混淆与加固对比 源码混淆与ipa文件混淆的区别、iOS代码保护与应用安全场景最佳实践
  • 鸿蒙Next ArkWeb网页多媒体开发实战:从基础到高级应用
  • ActiveMQ RocketMQ RabbitMQ Kafka选型及应用场景
  • 汽车网络安全 CyberSecurity ISO/SAE 21434 测试之二
  • pyAutoGUI 模块主要功能介绍-(3)截图与图像识别功能
  • 泛型(Generics)what why when【前端TS】
  • 优化神经网络模型以提升R²值至0.99的全面方案
  • AR眼镜:远程协作的“破局者”,让问题解决“云手帮”