The Intent section for the Command pattern in the Go4 book reads:

将请求封装为对象,从而使您可以将具有不同请求,队列或日志请求的客户端参数化,并支持可撤销的操作。

让我们分解其中的一些,并在游戏编程的上下文中对其进行研究。

参数化调用代码的能力

这使您可以动态配置调用命令并执行操作的事物。这也可以通过回调来实现。命令对象可以用作OO替换回调的一种语言,该语言不以您所需的方式支持它们(例如,不支持高阶函数或不支持闭包);但是,如果以后需要访问或操作与命令关联的状态,或者要支持更复杂的接口,则只需Execute()即可,拥有Command类可以提供帮助。

在本书中,在开发应用程序菜单框架的上下文中介绍了模式,其中菜单项可以通过Command进行配置。重要的一点是,菜单项不知道其作用或目标对象是什么-它不了解其执行的操作,只知道单击该菜单项时应该发生某些事情。

enter image description here

您可以更改此基本结构。例如,可以通过某种ID(并由其他组件获取)间接引用接收方。

在游戏中,尤其是在游戏AI中,一种非常相似的情况是您要支持脚本编写-命令可以封装用户提供的脚本(并且可能附带一些元数据,并且可能引用脚本引擎)。在这里,调用代码知道何时,在什么情况下执行脚本,但不知道该怎么做以及影响哪些实体。 (当然,还有其他方法可以做到)。 这促进了所涉及的不同系统(AI,脚本)之间的关注点分离。

而且,请考虑一些不那么奇特的东西。键绑定。可能有多个键(或不同输入设备上的多个触发器)调用同一操作,或者操作可能与上下文有关(同一键在不同情况下会执行不同的操作)。此外,玩家可以随时更改它们。解决此问题的一种方法是拥有一组命令对象,您可以将它们插入处理输入的系统中,并将它们与各种触发器动态关联。

排队请求的能力

一旦具备了将输入映射到命令的基础架构,就可以在AI系统中利用它来控制NPC。

现在,您说:

通常,在对AI进行编程时,您希望立即执行指令

好吧,不必在决策一刻就执行它们-只是在游戏循环的当前周期内。此外,如果游戏使用的是ECS模式,那么命令流方法可能是一个不错的选择。同样,某些游戏以与渲染器和游戏其余部分不同的更新速率运行其AI引擎,并且将AI输出作为命令排队可能是解决此问题的一种好方法。

支持记录

这可能意味着字面意义上的日志记录,但让我们进一步思考。日志是事件的记录流。可能会(在谨慎构造时)播放。开箱即用的回放和演示支持!添加一些计时元数据,并且还可以通过一些努力来支持诸如时间倒带机制之类的功能,在该机制中,玩家可以倒带时间(直至特定点)以再次尝试相同的场景(类似于《辫子》中可能的做法) ,或GRID 2)。

额外的东西

支持撤消/重做的能力很容易说明,因此我不再赘述。

您可以做的另一件有趣的事情是将其与Composite模式结合使用,然后使您拥有复合命令-由子命令组成。对于开发人员来说,这可能只是为您带来便利,但这也可以为构建编辑器提供支持,用户可以在GUI中构建这些复合命令,甚至可以将其整合到游戏中,玩家可以在其中构建自定义行为是某种机制的一部分-让游戏记住它们(因为您可以序列化和反序列化命令,包括复合命令)。

将命令视为对象或数据的另一个好处是,您可以灵活地并行执行其中的一些命令(如果任务是可并行化的),这可以提高性能。