首先說下目的,是爲了實現相似手柄的輸入功能。假設一個手柄有A/B兩個鍵,能夠輸入不一樣的指令而且能夠替換(好比吃血瓶/跳躍/射擊等操做)。除此以外還有一個額外的需求,就是能夠記錄玩家最近輸入的X次操做,而且能夠撤銷。node
咱們先寫一個Actor類,做爲被控制的主角,這裏只寫了HP一個字段,由於咱們下面暫時將A/B鍵的功能設爲加血和扣血。ide
public class Actor { public int HP; public Actor(int hp) { HP = hp; } }
而後寫好Command基類,須要設置一個被控制的Actor(遊戲中能夠替換主角/AI等),而且包含一個執行和撤銷的方法。測試
public class Command { protected Actor actor; public Command(Actor a) { actor = a; } ~Command() { } public virtual void Excute() { } public virtual void Undo() { } }
下面寫了一個CommandA,執行的操做是對某一個Actor加10點血量,除此以外還寫了一個CommandB,執行扣血,由於與CommandA差很少就不展現了。code
public class CommandA : Command { ~CommandA() { } public CommandA(Actor a) : base(a) { } public override void Excute() { actor.HP += 10; Debug.Log("actor 加了10hp, 如今hp: " + actor.HP); } public override void Undo() { actor.HP -= 10; Debug.Log("actor 撤銷了加血, 如今hp: " + actor.HP); } }
下面是要實現一個命令的棧,能夠記錄最近的X次命令(我假設的是五次),並能夠逐一撤銷。blog
public class CommandNode //命令棧中的節點,記錄的當前的命令以及它的上一個和下一個命令 { ~CommandNode() { Debug.Log("我被釋放了"); } public Command m_command; public Command Command{ get { return m_command; } } public CommandNode(Command command) { m_command = command; } public CommandNode preCommand; public CommandNode nextCommand; } public class CommandStack { private int m_iCapacity = 0; //stack容量 private int m_iCount = 0; //stack內命令數量 private CommandNode firstNode; //存儲的第一次的命令 private CommandNode lastNode; //最後一次命令 public CommandStack(int capacity) { m_iCapacity = capacity; } public bool IsEmpty() { return m_iCount == 0; } public void Push(Command command) { if(IsEmpty()) //若是stack爲空,將第一個命令和最後一個命令都設成當前這個 { CommandNode node = new CommandNode(command); node.preCommand = null; node.nextCommand = null; firstNode = node; lastNode = node; } else //stack不爲空,將當前的命令設爲最後的命令 { CommandNode node = new CommandNode(command); node.preCommand = lastNode; node.nextCommand = null; lastNode.nextCommand = node; lastNode = node; } m_iCount++; if (m_iCount > m_iCapacity) //命令數超過容量了,去除第一個 { firstNode = firstNode.nextCommand; firstNode.preCommand = null; m_iCount--; } } public Command Pop() { Command result = lastNode.Command; //返回最後一次命令 if (lastNode.preCommand != null) //若是最後一次命令以前還有命令,將其設爲最後的命令 { lastNode = lastNode.preCommand; lastNode.nextCommand = null; } else //若是沒有了,說明stack空了,將第一次和最後一次命令置空 { firstNode = null; lastNode = null; } m_iCount--; return result; } }
寫完上面的下面就是個人主要控制類了。遊戲
public class CommandPatternMain : MonoBehaviour { private Actor actor = new Actor(100); CommandStack commands = new CommandStack(5); Command command; Command tempCommand = null; private Command m_CommandA; private Command m_CommandB; private void Start() { SetCommands(); } private void SetCommands() { m_CommandA = new CommandA(actor); m_CommandB = new CommandB(actor); } private void Update() { command = InputHandler(); if(command != null) { command.Excute(); commands.Push(command); } if(Input.GetKeyDown(KeyCode.Space) && !commands.IsEmpty()) { tempCommand = commands.Pop(); if(tempCommand != null) tempCommand.Undo(); } } private Command InputHandler() { if (Input.GetKeyDown(KeyCode.A)) { return m_CommandA; } if (Input.GetKeyDown(KeyCode.B)) { return m_CommandB; } return null; } }
這個類裏有兩個固定的命令A和B,當玩家按下A和B對應的鍵位時執行這兩個命令。至於具體是什麼命令,咱們在SetCommands方法裏賦值了,固然遊戲進行中能夠隨時替換。每當玩家執行一次命令以後會推入一個容量爲5的命令棧,當玩家按下撤銷的按鍵時會Pop出最後一次命令,並執行Undo的方法。下面看看測試結果,咱們先加五次血,再扣三次血,再撤銷五次,而後再加五次血,再扣三次血,再撤銷五次,結果以下:ci