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

MyFramework:CommandSystem 命令系统的实现解析

在游戏项目里,系统之间互相调用是很常见的事情。

比如 UI 要关闭窗口,角色要移动,摄像机要缩放,某个对象要播放动画,某个系统要延迟执行一段逻辑。

最直接的写法当然是调用函数:

window.setVisible(false); camera.setOrthoSize(5.0f); obj.setPosition(pos);

这种写法简单,也很直观。

但项目复杂以后,直接调用会遇到一些问题。

有些操作需要延迟执行。

有些操作需要等到主线程执行。

有些操作需要统一打印日志。

有些操作需要执行前回调、执行后回调。

有些操作还没有执行,接收者就已经销毁了。

如果这些逻辑全部散落在业务代码里,后期会变得非常难维护。

所以在 MyFramework 中,我做了一个统一的命令系统:

CommandSystem

它的核心目的不是为了套一个“命令模式”,而是为了把操作的创建、延迟、执行、中断、回收和接收者生命周期统一管理起来。

项目地址:

GitHub - ZHOURUIH/MyFramework: Unity 商用级别开发框架,经过了多年经验沉淀.一个在unity上使用的网络游戏客户端开发框架,为unity所有使用方式提供完善的封装和管理,只需要专注于游戏逻辑的编写 · GitHub


一、为什么不直接调用函数

直接调用函数的问题,不在于它不能用,而在于它缺少统一生命周期。

例如一个窗口执行延迟关闭:

delay 0.5 秒后关闭窗口

如果 0.5 秒还没到,窗口已经被销毁了,这个延迟逻辑还要不要执行?

再比如一个角色执行移动命令:

角色移动到某个位置

如果命令还在等待执行,角色已经死亡或者离开场景,这个命令就不能继续访问原对象。

这些问题如果每个系统自己处理,就会出现大量重复判断。

CommandSystem 的作用就是把这些问题集中起来。

一次操作不再只是一次函数调用,而是一个带状态的命令对象。


二、Command 不是简单的 execute

在 MyFramework 中,一个 Command 不只是一个execute()函数。

它还会保存很多执行相关的信息,比如:

protected CommandReceiver mReceiver; protected float mDelayTime; protected bool mIgnoreTimeScale; protected bool mThreadCommand; protected bool mDelayCommand; protected EXECUTE_STATE mCmdState; protected LOG_LEVEL mCmdLogLevel;

这些字段说明一件事:

Command 是一个带生命周期的操作请求。

它不仅知道自己要执行什么,还知道:

  • 谁是接收者

  • 是否延迟执行

  • 是否忽略时间缩放

  • 是否来自线程命令

  • 当前是否已经执行

  • 是否需要输出日志

所以 CommandSystem 处理的不是“函数怎么调用”,而是“这个操作应该在什么时间、什么状态下执行,以及执行完以后如何清理”。


三、CommandReceiver 的作用

Command 一般不会孤立存在,它通常会绑定一个接收者。

这个接收者就是CommandReceiver

可以简单理解为:

Command 负责描述要做什么 CommandReceiver 负责接收这个命令 CommandSystem 负责什么时候执行这个命令

这样做的好处是,命令和具体系统之间不会完全写死。

比如窗口、摄像机、场景对象、可移动对象,都可以作为命令接收者。

CommandSystem 不需要知道每个接收者内部具体怎么实现,它只负责统一调度命令。


四、立即命令的执行流程

普通命令进入 CommandSystem 后,会走一套统一流程。

大致可以理解为:

创建命令 ↓ 绑定接收者 ↓ 设置命令状态 ↓ 执行开始回调 ↓ 调用 execute ↓ 执行结束回调 ↓ 回收到对象池

这和直接调用函数最大的区别是:

直接调用只关心“执行”。

CommandSystem 还关心“执行前”和“执行后”。

比如命令执行前可以统一打印日志、记录状态、进入性能采样。

命令执行后可以统一回调、清理状态、回收到对象池。

这些逻辑如果全部写在业务函数里,会非常分散。

统一放到 CommandSystem 中,命令的行为就会更加可控。


五、延迟命令的处理方式

CommandSystem 中比较重要的一部分是延迟命令。

很多游戏逻辑都需要延迟执行,比如:

  • 延迟关闭窗口

  • 延迟播放动画

  • 延迟执行引导步骤

  • 延迟切换状态

  • 延迟发送某个事件

如果每个系统都自己维护计时器,就会变得很乱。

所以延迟命令会进入 CommandSystem 统一管理。

流程大致是:

pushDelayCommand ↓ 加入延迟命令列表 ↓ 每帧更新剩余时间 ↓ 时间到达后加入执行列表 ↓ 统一执行命令 ↓ 执行完回收到对象池

这样所有延迟操作都可以通过统一入口推进。

业务系统只需要提交命令,不需要自己额外维护一套延迟列表。


六、为什么需要命令缓冲区

在 CommandSystem 中,命令并不是随便直接插入正在遍历的列表。

因为有些命令可能来自不同调用时机,甚至可能来自子线程。

如果在主线程遍历命令列表时,另一个地方同时往列表里添加或删除命令,就可能导致列表状态不稳定。

所以 MyFramework 中会把命令缓冲分成不同阶段处理。

可以简单理解为:

输入缓冲 ↓ 主线程同步 ↓ 处理缓冲 ↓ 本帧执行列表

输入缓冲负责收集新提交的命令。

处理缓冲负责主线程当前正在推进的延迟命令。

执行列表负责本帧真正要执行的命令。

这样可以避免一边遍历一边修改同一个列表。

这也是命令系统里比较重要的一个细节。

它不是为了把代码写复杂,而是为了让命令提交和命令执行之间有清晰边界。


七、命令如何中断

延迟命令还有一个问题:

命令提交以后,还没执行之前,可能需要取消。

比如:

  • 窗口已经关闭

  • 角色已经销毁

  • 状态已经切换

  • 之前排队的操作已经不再需要

所以 CommandSystem 需要支持中断命令。

命令对象本身有分配 ID,也就是AssignID

通过这个 ID,可以找到还在等待中的命令。

如果命令还没有进入执行阶段,就可以直接移除并回收。

如果命令已经进入本帧执行列表,就不能随便在遍历过程中删除,只能让它失效,避免继续访问接收者。

这类细节在小项目里不明显,但在长期项目里很重要。

因为延迟逻辑越多,取消和失效处理就越多。

如果这些逻辑全部靠业务自己判断,很容易漏。


八、接收者销毁后如何处理命令

CommandSystem 里还有一个非常实际的问题:

命令的接收者销毁了,命令怎么办?

比如一个 UI 窗口关闭时,之前可能还有一些延迟命令没有执行。

如果这些命令继续执行,就可能访问已经销毁的窗口对象。

所以接收者销毁时,需要通知 CommandSystem。

CommandSystem 会清理和这个接收者相关的未执行命令。

可以理解为:

接收者销毁 ↓ 通知 CommandSystem ↓ 查找等待中的命令 ↓ 移除属于该接收者的命令 ↓ 已经进入执行列表的命令让其失效

这样可以避免很多延迟调用导致的空引用问题。

这也是 CommandSystem 比直接延迟调用函数更安全的地方。

它知道命令属于谁,也能在接收者销毁时统一处理。


九、命令对象也走对象池

Command 本身也是对象。

如果每次执行命令都 new 一个对象,用完就丢给 GC,那高频命令下也会产生额外开销。

所以 MyFramework 中的 Command 也会走对象池。

这正好和上一篇 ClassPool 的设计接上。

命令执行完以后,会被回收到对象池中。

如果是主线程命令,就回收到主线程 ClassPool。

如果是线程命令,就回收到线程安全对象池。

这意味着 Command 也必须正确实现resetProperty

因为命令对象下一次还会被复用。

它需要清理:

  • 接收者

  • 延迟时间

  • 回调

  • 执行状态

  • 日志等级

  • 线程命令标记

  • 延迟命令标记

  • 执行结果

否则下次从对象池取出命令时,就可能带着上一次的残留状态。

这再次说明:

对象池复用的核心不是“对象回收了没有”,而是“对象回收前有没有清干净”。


十、CommandSystem 和其他系统的关系

CommandSystem 并不是孤立模块。

它和 MyFramework 里的很多系统都有关系。

例如 GlobalTouchSystem 判断某个对象被点击以后,后续可以通过命令去驱动 UI 或对象行为。

比如:

点击按钮 ↓ GlobalTouchSystem 判断按钮是否能响应 ↓ 按钮逻辑提交命令 ↓ CommandSystem 统一执行

ClassPool 则负责命令对象的创建和回收。

所以这几个模块之间可以形成一个完整链路:

GlobalTouchSystem 负责判断谁响应输入 CommandSystem 负责统一执行操作 ClassPool 负责命令对象生命周期

这也是框架设计里比较重要的一点。

一个系统不应该把所有事情都做完。

GlobalTouchSystem 不负责具体业务操作。

CommandSystem 不负责判断点击命中。

ClassPool 不关心命令语义。

每个系统只负责自己的边界。


十一、这套方案解决的具体问题

CommandSystem 解决的不是“怎么把函数调用包装起来”。

它主要解决的是操作执行过程中的生命周期问题。

具体包括:

  • 操作可以统一提交

  • 操作可以立即执行

  • 操作可以延迟执行

  • 延迟操作可以在统一 update 中推进

  • 命令可以记录执行状态

  • 命令可以绑定接收者

  • 接收者销毁后,可以清理相关命令

  • 未执行的延迟命令可以被中断

  • 命令执行前后可以有统一回调

  • 命令执行日志可以统一控制

  • 命令对象可以通过对象池复用

这些能力如果分散在各个业务系统里,每个地方都要重复写一遍。

而 CommandSystem 的价值,就是把这些通用流程收敛到框架层。


结语

CommandSystem 的价值,不是为了把简单函数调用变复杂。

如果只是单纯调用一个函数,直接调用当然更简单。

但在长期游戏项目里,很多操作都不只是“立刻执行一下”这么简单。

它可能需要延迟。

可能需要取消。

可能需要等到主线程。

可能需要知道接收者是否已经销毁。

可能需要执行前后回调。

可能需要统一日志。

可能还需要对象池回收。

所以 MyFramework 中的 CommandSystem,本质上是给操作请求加上了一套生命周期。

它把操作从一行函数调用,变成一个可管理的命令对象。

这样做的目的不是形式上套设计模式,而是让跨系统操作、延迟操作和可取消操作都能被框架统一管理。

这就是 CommandSystem 在 MyFramework 中的核心作用。

http://www.jsqmd.com/news/1034045/

相关文章:

  • 10分钟搞定黑苹果:OpCore-Simplify图形化OpenCore配置工具终极指南
  • Windows系统安装Silvaco TCAD 2018完整指南:从环境配置到故障排查
  • 终极解决方案:如何让魔兽争霸3在现代Windows系统完美运行
  • 解锁Unity全功能体验:UniHacker如何实现跨平台破解方案?
  • 2026年不错的GEO优化服务商用户力荐 - myqiye
  • 暗黑破坏神2存档修改器终极指南:打造完美角色的完整教程
  • 脉冲神经网络与事件视觉的自监督学习新范式
  • 微信评选投票小程序怎么弄,西瓜评选+云帆投票+腾讯投票,投票平台深度对比测评 - 投票小程序
  • 旋转夹爪怎么选型?2026年主流旋转夹爪生产厂家盘点 - 品牌深度评测
  • 机器人夹爪有哪些选型技巧?2026年通用机器人夹爪品牌参考 - 品牌深度评测
  • 有实力的劳动纠纷律师推荐,炜衡律所刘纪伟团队 - myqiye
  • Windows 11 26H1预览版部署与开发环境配置全攻略
  • 2026 扬州全域彩钢瓦翻新修缮四大权威企业深度测评|金属屋面防水除锈喷漆 TOP4 榜单 + 厂房业主专属避坑全指南 - 本地便民网
  • 2026 江苏镇江全域彩钢瓦修缮四大权威企业深度测评|金属权威企业深度测评|金属屋面除锈防水喷漆 TOP4 榜单 + 厂房业主专属避坑全指南 - 本地便民网
  • 双黑洞系统GRMHD模拟:原理、挑战与应用
  • 从WinError 10061到LangChain安装成功:代理、防火墙与网络环境排查全攻略
  • 2026 江苏盐城市全域彩钢瓦修缮公司 TOP4 权威测评|沿海盐雾专用翻新防水服务商优劣对比 + 厂房业主专属避坑全攻略 - 本地便民网
  • 7天打造你的科研知识库:Obsidian终极配置指南
  • 力控夹爪选型小贴士:2026年专业力控夹爪生产厂家推荐 - 品牌深度评测
  • 如何快速打造你的JavaScript智能机器人:Stack-chan全功能指南
  • 可复现性危机:从环境漂移到知识断层的系统性解法
  • 如何利用免费云资源搭建属于自己的Web前端学习沙盒
  • 旋转夹爪如何找优质厂商?2026年主流旋转夹爪生产厂家名单 - 品牌2026
  • Python字节码逆向工程:新一代pycdc工具深度解析与架构设计
  • 百日筑基篇—— ggplot2八大要素实战拆解(R语言可视化进阶)
  • 2026免费录音转文字手把手教程:无限制网页版、长音频免费转换一键搞定
  • 3分钟掌握VoiceCraft:AI语音编辑如何重塑内容创作工作流
  • 向量引擎 API 中转站怎么选?正规、稳定、企业级向量接口的完整选型指南
  • 隐形车衣哪家好?盐城壹+车库,用心服务,品质至上 - myqiye
  • LinkSwift网盘直链下载助手:一键获取真实下载地址,彻底告别网盘限速烦恼