上一章节介绍过了命令模式,这一篇文章就简单的做一个小案例来巩固学习
搭建场景
简单的搭建一个场景就行 ,随便准备一个物体放在场景中位置Reset一下即可。
代码编写
- 定义接口(或者抽象类)ICommand 用来规范Command的行为。注意在命令模式中命令是桥接作用负责接受者和执行者之间的联调。所以一般会有很多的命令,每个命令都会有ICommand规范的方法同时也可以添加其他的方法。
public interface ICommand{
void Execute();
void UnExecute();
}
- 实现定义的接口(或者抽象类) 同时为了具有这种桥接的作用,MyCommand 需要持有Receiver
public enum Direction{
Left,
Down,
Right,
Up
}
public class MyCommand : ICommand{
private Receiver _receiver;
private Direction _direction;
private GameObject _moveObj;
private float _distance;
public MyCommand(Direction direction,Receiver receiver,GameObject moveObj,float distance){
this._receiver = receiver;
this._direction = direction;
this._moveObj = moveObj;
this._distance = distance;
}
public void Execute(){
_receiver.OperationDirection(_moveObj,_direction,_distance );
}
public void UnExecute(){
_receiver.OperationDirection(_moveObj,InverseDirection(_direction),_distance );
}
private Direction InverseDirection(Direction direction){
switch(direction){
case Direction.Left:
return Direction.Right;
case Direction.Right:
return Direction.Left;
case Direction.Up:
return Direction.Down;
case Direction.Down:
return Direction.Up;
}
}
public override void ToString(){
return $"{_moveObj.name}:{DirectionStr(_direction)}:{_distance.ToString()}";
}
private string DirectionStr(Direction dircteion) {
switch (dircteion)
{
case Direction.Left:
return "Left";
case Direction.Right:
return "Right";
case Direction.Up:
return "Up";
case Direction.Down:
return "Down";
default:
return default;
}
}
}
3.接受者,接受者的意思是接受命令执行自身的函数
public class Receiver{
public void OperationDirection(GameObject moveObj,Direction direction,float distance){
switch(direction){
case Direction.Left:
MoveX(moveObj,-distance);
break;
case Direction.Right:
MoveX(moveObj,distance);
break;
case Direction.Up:
MoveY(moveObj,distance);
break;
case Direction.Up:
MoveY(moveObj,-distance);
break;
}
}
private void MoveX(GameObject moveObj,float distance){
var tempPos = moveObj.transform.position;
tempPos .x+=distance;
moveObj.transform.position = tempPos;
}
private void MoveY(GameObject moveObj,float distance){
var tempPos = moveObj.transform.position;
tempPos.y+=distance;
moveObj.transform.position = tempPos;
}
}
4.执行者,挂载在场景中的任意物体上(建议放空物体上)负责代码的执行 调度
public class InputHandler : MonoBehaviour{
private Receiver _receiver;
[SerializeField]
[Tooltip("移动距离")]
private float distance = 1f;
private List<ICommand> commands = new List<ICommand>(); // 存储命令方便回溯
private int currentCommandNum = 0; // 当前执行的命令
public GameObject moveObj; //控制的物体上面的那个Move直接拖到这里进行绑定
private void Start()
{
_receiver= new Receiver();
// 空处理 可写可不写
}
private void Move(Direction direction){
var command = new MyCommand(direction,_receiver,moveObj,distance);
command.Execute();
commands.Add(command);
currentCommandNum++;
}
private void Undo(){
if(currentCommandNum > 0 ){
currentCommandNum--;
MyCommand command= (MyCommand )commands[currentCommandNum];
command.UnExecute();
}
}
private void Redo(){
if (currentCommandNum < commands.Count) {
MyCommand command= (MyCommand )commands[currentCommandNum];
currentCommandNum++;
command.Execute();
}
}
void OnGUI()
{
string label = " start";
if (currentCommandNum == 0)
{
label = ">" + label;
}
label += "\n";
for (int i = 0; i < commands.Count; i++)
{
if (i == currentCommandNum - 1)
label += "> " + commands[i].ToString() + "\n";
else
label += " " + commands[i].ToString() + "\n";
}
GUI.Label(new Rect(0, 0, 400, 800), label);
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.UpArrow)|| Input.GetKeyDown(KeyCode.W))
{ moveUp(); }
if (Input.GetKeyDown(KeyCode.DownArrow) || Input.GetKeyDown(KeyCode.S))
{ moveDown(); }
if (Input.GetKeyDown(KeyCode.LeftArrow) || Input.GetKeyDown(KeyCode.A))
{ moveLeft(); }
if (Input.GetKeyDown(KeyCode.RightArrow) || Input.GetKeyDown(KeyCode.D))
{ moveRight(); }
if (Input.GetKeyDown(KeyCode.R))
{ Redo(); }
if (Input.GetKeyDown(KeyCode.U))
{ Undo(); }
}
void moveUp() { Move(Direction.Up); }
void moveDown() { Move(Direction.Down); }
void moveLeft() { Move(Direction.Left); }
void moveRight() { Move(Direction.Right); }
}
现在就基本上已经做完了,是一个很简单的案例用来巩固学习命令模式