“将一个请求封装成一个对象,从而允许你使用不同的请求、队列或日志将客户端参数化,同时支持请求操作的撤销与恢复”
回放在游戏中很常见,一个很简单的实现方法就是记录每一帧的游戏状态以便能够回放,但是这样会使用大量的内存。
实际上,许多游戏会记录每一帧每个实体所执行的一系列命令,为了回放游戏,引擎只需要模拟正常游戏的运行,执行预先录制的命令即可。
如果我们把命令序列化,我们便可以通过网络发送数据流,可以把玩家的输入,通过网络发送到另外一台机器上,然后进行回放,这是多人网络游戏很重要的一部分。
class Command
{
public:
virtual ~Command();
virtual void execute(GameActor& actor) = 0;
};然后为每个不同的游戏动作创建子类。
class JumpCommand : public Command
{
public:
virtual void execute(GameActor& actor){
actor.jump();
}
};
class FireCommand : public Command
{
public:
virtual void execure(GameActor& actor){
actor.fireGun();
}
};人工智能----->命令流----->角色undo撤销的支持。为Command抽象undo方法。
class MoveUnitCommand : public Command
{
public:
MoveUnitCommand(Unit* unit, int x, int y): unit_(unit), x_(x), y_(y)
{
}
virtual void execute()
{
xBefore_ = unit_->x();
yBefore_ = unit_->y();
unit_->moveTo(x_, y_);
}
virtual void undo()
{
unit_->moveTo(xBefore_, yBefore_);
}
private:
Unit* unit_;
int x_, y_;
int xBefore_, yBefore_;
};可以拉成双向链表
older CMD<-->CMD<-->CMD<-->CMD<-->CMD<-->CMD newer
undo current redo 不同的语言可能有不同的风格,选择OOP还是函数式编程也是不同的,例如在JavaScript中可以这么做。
function makeMoveUnitCommand(unit, x, y)
{
// ...
return function(){
unit.moveTo(x, y);
}
}通过闭包来添加对撤销的支持
function makeMoveUnitCommand(unit, x, y){
var xBefore, yBefore;
return{
execute: function(){
xBefore = unit.x();
yBefore = unit.y();
unit.moveTo(x, y);
},
undo: function(){
unit.moveTo(xBefore, yBefore);
}
};
}