命令模式
命令模式是具现化的方法调用,是一种回调的面向对象实现。
例子
玩家自定义配置按键的功能
如下为常见的简单实现
if(Input.GetKeyDown(KeyCode.Space))
Debug.Log("Jump");
else if(Input.GetKeyDown(KeyCode.LeftArrow))
Debug.Log("Left");
else if(Input.GetKeyDown(KeyCode.RightArrow))
Debug.Log("Right");
首先定义基类保存不同功能所绑定的按键
public class InputCommandBase
{
public KeyCode curBindingInputKeycode;
public virtual void Execute()
{
//按键对应操作
}
}
定义不同子类实现不同的按键功能
public class InputJump : InputCommandBase
{
public InputJump(KeyCode bindingInputKeyCode)
{
curBindingInputKeycode = bindingInputKeyCode;
}
public override void Execute()
{
base.Execute();
Debug.Log("命令模式:Jump");
}
}
public class InputLeft : InputCommandBase
{
public InputLeft(KeyCode bindingInputKeyCode)
{
curBindingInputKeycode = bindingInputKeyCode;
}
public override void Execute()
{
base.Execute();
Debug.Log("命令模式:Left");
}
}
public class InputRight : InputCommandBase
{
public InputRight(KeyCode bindingInputKeyCode)
{
curBindingInputKeycode = bindingInputKeyCode;
}
public override void Execute()
{
base.Execute();
Debug.Log("命令模式:Right");
}
}
通过命令模式将输入处理部分这样处理
public class InputTest : MonoBehaviour
{
private InputJump InputJump = new InputJump(KeyCode.Space);
//此处将左右键所绑定的功能对调
private InputRight InputRight = new InputRight(KeyCode.LeftArrow);
private InputLeft InputLeft = new InputLeft(KeyCode.RightArrow);
void Update()
{
//一般简单实现
if(Input.GetKeyDown(KeyCode.Space))
Debug.Log("Jump");
else if(Input.GetKeyDown(KeyCode.LeftArrow))
Debug.Log("Left");
else if(Input.GetKeyDown(KeyCode.RightArrow))
Debug.Log("Right");
//简单命令模式实现
if (Input.GetKeyDown(InputJump.curBindingInputKeycode))
InputJump.Execute();
else if (Input.GetKeyDown(InputRight.curBindingInputKeycode))
InputRight.Execute();
else if (Input.GetKeyDown(InputLeft.curBindingInputKeycode))
InputLeft.Execute();
}
}
以前每个输入直接调用函数,现在会有一层间接寻址。
如此就简单的通过命令模式实现了按键配置的功能。
简单实现操作对象间的切换
在基类中为按键功能传入当前所控制角色的参数。
public class InputCommandBase
{
public KeyCode curBindingInputKeycode;
/// <summary>
/// 扩展按键执行方法,增加当前所控制的角色参数。
/// </summary>
/// <param name="rigidbody"></param>
public virtual void Execute(Rigidbody rigidbody)
{
//按键对应操作
}
public virtual void Execute()
{
//按键对应操作
}
}
在子类当中简单实现对应功能。
public class InputJump : InputCommandBase
{
public InputJump(KeyCode bindingInputKeyCode)
{
curBindingInputKeycode = bindingInputKeyCode;
}
public override void Execute( Rigidbody rigidbody)
{
rigidbody.AddForce(Vector3.up * 5, ForceMode.Impulse);
Debug.Log("命令模式:Jump");
}
}
通过传入不同的对象从而实现简单的控制对象切换。
public class InputTest : MonoBehaviour
{
//***上文InputTest内容省略
//简单存储可控制的所有对象
public Rigidbody[] canControlRigs;
private Rigidbody curControlRig;
private void Start()
{
//初始定义当前可操作的对象
curControlRig = canControlRigs[0];
}
void Update()
{
//***上文InputTest内容省略
//简单切换控制对象
if(Input.GetKeyDown(KeyCode.Tab))
{
curControlRig = curControlRig == canControlRigs[0] ? canControlRigs[1] : canControlRigs[0];
Debug.Log("切换当前控制的游戏对象:" + curControlRig.name);
}
//根据传入的对象进行操作
if (Input.GetKeyDown(InputJump.curBindingInputKeycode))
InputJump.Execute(curControlRig);
}
}
当前实现简单的操作对象切换。
我们可以在AI和角色之间使用相同的命令模式。
在此基础上可以极灵活地完成AI和控制角色间的解耦。 我们可以对不同的角色使用不同的AI,或者为了不同的行为而混合AI。 例如想要一个更加有攻击性的AI,就可简单为该AI插入一个更加有攻击性的命令。
甚至可以为玩家操控的角色添加AI的命令行为,在游戏展示阶段,也是十分方便的操作。
撤销和重做
在此基础上可以通过保存每次操作前当前的游戏对象的各个状态,从而实现在进行操作命令后通过对上一状态的还原实现撤销和重做的功能。
若想多次重做,则可以将每次记录的操作添加在指令列表中。
当玩家选择“撤销”,我们撤销现在的命令,将代表当前的指针往后退。 当他们选择“重做”,我们将代表当前的指针往前进,执行该指令。 如果在撤销后选择了新命令,那么清除命令列表中当前的指针所指命令之后的全部命令。
想要了解撤销和重做对应实现的,可以简单参考下面这个文章。