在遊戲編程裏面,有一個經常會被用到的設計模式-命令模式。
我對設計模式的理解是
1、爲解決問題而生。
2、有大致流程,但是沒有固定格式
3、爲了溝通方便。
在遊戲編程裏面,或者軟件開發裏面,最能體現命令模式的應用場景是
"撤銷"與"再做"
在策略遊戲裏面,有時候我們會提供給玩家去模擬下一步的功能,在他還沒確定之前都是能夠撤銷我們的行爲的。比如象棋,比如五子棋,或者在商店系統的時候,玩家購買完東西后悔了,我們可以讓玩家去撤銷操作。
在編寫遊戲工具給策劃同事使用的時候,沒有撤銷功能的話會被親愛的策劃罵成狗的。
。。。
等等上面的需求出現之後,我們就可以考慮運用我們的命令模式來解決這個問題。
命令模式的宗旨是讓命令類化,爲了解耦,命令類將利用ConreteCommand類脫離宿主(接受命令的人,Reciver)的束縛,僅提供的是能夠傳入宿主的方法,自成一體。而命令與宿主之間的聯繫是靠一個Invoker來進行命令分發到宿主的。,Invoker裏面包涵類的實例化,實例化的時候才掛鉤命令與宿主。實例化命令之後就能夠進行命令的調用了。
而作爲最上層的調用客戶,我們就是利用Invoker來進行操作的。
在我的這個例子裏面,要演示的是如何利用命令模式去實現回退與重複。
小方塊能夠在移動之後利用UNDO返回之前的地點,也能利用REDO繼續最後一步的時候的方向。
ClickTest.cs 按鈕操作的類,Client
Command.cs 命令的抽象
ConcreteCommands.cs 具體的命令。
Cube.cs 方塊的類,類裏有各個方向移動的方法而已。
CubeController.cs 這傢伙就是Invoker了,裏面有一個命令的數組,保存命令只用,還有因爲要去關聯我們宿主,必須要有屬性指向我們的Cube.Invoker的調用分三塊,Undo,Redo,Go.分別對應三大類型的移動。
CubeEvent.cs 只是一個Enum而已,定義我們的方向。
鏈接:http://pan.baidu.com/s/1mg3Qgvm
附錄代碼:
using UnityEngine;
using System.Collections;
public class ClickTest : MonoBehaviour {
public GameObject user;
// Use this for initialization
void Start () {
}
public void LeftClick()
{
user.GetComponent<CubeController>().LetCubeMove((int)MoveEvent.left);
}
public void RightClick()
{
user.GetComponent<CubeController>().LetCubeMove((int)MoveEvent.right);
}
public void UpClick()
{
user.GetComponent<CubeController>().LetCubeMove((int)MoveEvent.up);
}
public void DownClick()
{
user.GetComponent<CubeController>().LetCubeMove((int)MoveEvent.down);
}
public void UndoClick()
{
user.GetComponent<CubeController>().Undo();
}
public void RedoClick()
{
user.GetComponent<CubeController>().Redo();
}
}
using UnityEngine;
using System.Collections;
//Invoker
public class CubeController : MonoBehaviour {
public GameObject _cube;
private ArrayList commands = new ArrayList();
private int current = 0;
public void Redo()
{
if (current>0)
{
Debug.Log("I can Redo now");
((MoveCommand)commands[commands.Count-1]).execute();
commands.Add(commands[commands.Count - 1]);
current++;
}
else
{
Debug.Log("當前沒有前置行爲");
}
}
public void Undo()
{
//Debug.Log("Undo " + levels + "levels");
if (current > 0)
{
Debug.Log("Current comm" + current);
int bakindex = current;
((MoveCommand)commands[--current]).unexecute();
Debug.Log("往前一步的下標:"+bakindex+",當前下標:"+current);
commands.RemoveAt(bakindex-1);
}
}
public void LetCubeMove(int move)
{
ICommand comm = new MoveCommand(move, _cube);
comm.execute();
commands.Add(comm);
Debug.Log("總命令數爲:"+commands.Count);
current++;
}
}
using UnityEngine;
using System.Collections;
//Reciver Cube
public class Cube : MonoBehaviour {
public void OnMove(int move)
{
switch (move)
{
case 0 :
MoveForward();
break;
case 1:
MoveBack();
break;
case 2:
MoveLeft();
break;
case 3:
MoveRight();
break;
}
}
public void MoveForward()
{
gameObject.transform.localPosition += new Vector3(0, 0, 1);
}
public void MoveBack()
{
gameObject.transform.localPosition += new Vector3(0, 0, -1);
}
public void MoveLeft()
{
gameObject.transform.localPosition += new Vector3(-1, 0, 0);
}
public void MoveRight()
{
gameObject.transform.localPosition += new Vector3(1, 0, 0);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
//ConcreteCommand 定義一個接受者和行爲之間的弱耦合
class MoveCommand :ICommand
{
//Cube is a Reciver
private GameObject Cube;
public int _move;
public MoveCommand(int move,GameObject cube)
{
this.Cube = cube;
_move = move;
}
public void execute()
{
Cube.GetComponent<Cube>().OnMove(_move);
}
public void unexecute()
{
Cube.GetComponent<Cube>().OnMove(Undo(_move));
}
public int Undo(int move)
{
int UnMove = -1;
switch (move)
{
case (int)MoveEvent.up:
UnMove=(int)MoveEvent.down;
break;
case (int)MoveEvent.down:
UnMove=(int)MoveEvent.up;
break;
case (int)MoveEvent.left:
UnMove=(int)MoveEvent.right;
break;
case (int)MoveEvent.right:
UnMove=(int)MoveEvent.left;
break;
}
return UnMove;
}
}
using UnityEngine;
using System.Collections;
//創建了一個具體命令(ConcreteCommand)對象並確定其接收者
interface ICommand {
void execute();
void unexecute();
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public enum MoveEvent
{
up,
down,
left,
right
}