游戏代码浅读室/#2 命令模式
一、概述
本系列专栏为笔者学习体会随笔 没有绝对专业性,主要内容为对游戏设计模式及其他内容的理解和应用实例。
注:设计模式只是一种简单的设计思路,我们应该活用思路而不是按图索骥,适当修改能更好地应用于自己的游戏中。
在GoF(Gang of Four,四人组)的定义下,设计模式一共有23种常见的模式,这些设计模式分为三大类:创建型模式(Creational Pattern)、结构型模式(Structural Pattern)和行为型模式(Behavioral Pattern)。我们今天的主角就是行为型模式中的 命令模式(Command Pattern)。
二、初识命令模式
命令模式可以说是我在游戏设计中最喜欢的模式了,合理地使用命令模式在你的游戏项目中,可以让你的代码更加的优雅,系统更具有拓展性,例如 你可以使用命令模式去设计你的角色的技能,这样子你在后续想要添加更多技能的时候都可以随意添加。
“ 命令就是一个对象化(实例化)的方法调用。”
简单来说,命令模式就是将一个方法包装成了一个对象,也就是“对象化的方法调用”。在一款RPG游戏中,我们的玩家可以在战斗中对自己的角色进行操作,这些操作包括 移动、攻击、技能、防御、道具、逃跑等等,而这些角色动作就是一系列的指令对象,当玩家指挥一名角色进行攻击的时候 就是在为这名角色发布指令,这名角色将会接收指令并执行 对敌人进行进攻。

因此在命令模式中,一般会有四种类,分别为:
1.Command (指令类):定义一个基类来代表一个可触发的游戏命令,一般会将其定义为一个抽象类或者接口(ICommand)。
2.ConcreteCommand(具体指令类):对Command类进行具体的实现,主要内容是定义该指令的具体内容。
3.Invoker (指令调用者类):负责触发调用命令,通知对象进行命令执行。
4.Receiver (指令接收类者):负责接收命令并调用命令,执行命令内容。

三、动动手
在你了解过命令模式的逻辑后,现在就可以动动手为你的角色编写指令了。
首先来编写Command基类,这里笔者的建议是将其设计为一个Interface而不是抽象类,这样子的设计能够让指令实现更具拓展性,通过实现接口而不是继承结构 让具体指令将能实现更多的功能,同时避免了复杂或较深的继承结构,也就是 组合优于继承(Prefer Composition Over Inheritance)的思想。
于是,我们就可以实现一个具体的攻击指令,可以看到这里因为 ICommand 的接口特性,我们可以将具体指令包装成一个SO 并实现指令内容,在实现指令的时候 我们的推荐做法是将接收者对象作为参数传入指令当中,并在执行方法中 对接收者对象进行操作,这样以便将角色和命令解耦,我们的命令内容将会是 “xxx将进行进攻” 而不是 “只负责进攻”,当然这里只是演示 不一定是最佳做法:
让我们再写一个防御指令:
我们还可以考虑将攻击和防御种种能力再抽象出来成一个Interface,这样子只有具备 IAttack 或 IDefence 能力的 Receiver 才能使用这些指令,这里就不继续拓展了。
接着,我们就需要一个调用者(Invoker)来发布指令,一个接收者(receiver)来接收并执行指令:
到此为止,一个较为完整的简单命令模式就写好了,思路也是比较清晰的。
四、更强大的
你以为命令模式的功能只有现在这一种吗?那你就小瞧了强大的命令模式了。我们可以依据命令模式的特性 来实现取消命令 回溯的功能,而这只需要我们为命令系统加上一点记忆的功能。
总之命令模式是一个相当有趣且好用的设计模式,我们可以使用这个模式丰富自己系统的拓展性,推荐大家使用并且研究出适合自己游戏的命令系统。
还有一种有关于命令模式的思想,大概是将各种命令作为能力赋予给角色,详情可以看这个视频:
