命令模式
命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
我们在游戏设计中使用命令模式有以下好处:
? 1.可以把游戏行为和游戏角色解耦合,易于分别维护游戏角色和游戏行为的代码,更新其一时不需要或只需要少量改动另一的代码
? 2.可以通过记录产生过的游戏指令序列来记录整个游戏过程,生成体积很小的游戏回放文件
? 3.易于实现游戏中的撤销功能
? 4.易于编写AI操控游戏角色
示例
以坦克大战为例(这里使用Unity做示范):
1.首先我们得有一个坦克类的脚本,挂载在坦克的预制件上
class Tank : MonoBehaviour
{
GameObject t;
Rigidbody2D rb;
public float speed;
void Start()
{
rb = transform.GetComponent<Rigidbody2D>();
}
public void Move(Vector2 v)
{
rb.velocity = v;
}
}
这个类负责提供操控一个坦克实例的函数,以及存储该坦克实例的各种参数。
2.然后我们设置一个命令类,以最基本的移动命令为例(大部分游戏物体都具有移动这一游戏行为)
interface Command
{
void Execute(ref Tank t);
};
class MoveCommand : Command
{
private Vector2 v;
private static MoveCommand instance = new MoveCommand();
private MoveCommand(){
v = Vector2.zero;
}
public static ref MoveCommand getInstance(){
return ref instance;
}
public void Setv(Vector2 _v)
{
v = _v;
}
public void Execute(ref Tank t)
{
t.Move(v);
}
}
这里又使用了所谓单例模式:将移动命令类的构造函数声明为private,可以阻止其被初始化为多个实例,在内部生成一个实例然后通过getInstance返回,这样可以保证全局只有一个移动命令类的实例,好处是免去了在各个地方生成和销毁实例的开销,并且可以避免多个命令类实例同时对一个实例下达命令导致其行为冲突的可能性。
我们没有在命令类中绑定某一个实例,而是在Execute中直接传入,这样可以用同样的配置(比如这里是速度的配置)批量对任意数量的游戏实例执行命令。
而对于特定的某一个实例如果需要单独记录其配置,则可以在Tank类中增加相关的成员来记录,并在命令类中增加一个开关:使用实例中的配置还是指令中的配置。需要注意更改其配置也应通过相应命令类来实现。
在Execute中记录当前的命令类实例,执行的对象实例,以及执行时的时间,即可生成指令序列形式的游戏回放,也可以实现Undo(撤销)操作
我们再设置一个Player类,这个类用于接收玩家从外设输入的指令。
public class Player : MonoBehaviour
{
KeyCode[] keymap;
Vector2[] dv;
Tank t;
MoveCommand mc;
void Start()
{
keymap = new KeyCode[] { KeyCode.W, KeyCode.S, KeyCode.A, KeyCode.D };
dv = new Vector2[] { Vector2.up,Vector2.down,Vector2.left,Vector2.right};
mc = MoveCommand.getInstance();
}
public void Bind(ref Tank _t)
{
t = _t;
this.transform.parent=t.transform;
}
void MoveControl()
{
for(int i=0;i<4;i++)
{
if (Input.GetKey(keymap[i]))
{
mc.Setv(t.speed*dv[i]);
mc.Execute(ref t);
return;
}
}
mc.Setv(Vector2.zero);
mc.Execute(ref t);
}
private void FixedUpdate()
{
MoveControl();
}
}
在本游戏中,玩家要控制一个坦克,我们可以在Player类里绑定一个游戏场景中的坦克的实例,这样当玩家需要重生或者更换坦克时就非常方便.
如果要支持多人游戏,可以生成多个Player实例绑定不同的坦克实例来实现,不需要添加额外的代码。
当Player实例接收到玩家输入的指令时, 就通过命令类把绑定的坦克实例作为参数传入,让命令类驱动坦克类执行命令。
接下来只要生成一个Tank实例然后调用Player的Bind函数绑定即可
|