Unity与设计模式之命令模式

命令模式:

将一个请求封装成一个对象,从而允许你使用不同的请求队列日志将客户端参数化。同时支持请求操作的撤销恢复

 命令就是面向对象化的回调。

最常见的便是用在输入控制上。

我们可以将输入的信号转换成对应的指令,存入命令队列中,依次执行。

下面是一个小例子:

在Unity中,主要用到了这几个脚本。

代码部分:

Unit:所有单位的基类,封装了通用的高级方法。后续如果新建不同的单位类型从这个类继承就可以了。简便起见,只预设了两个方法。

public class Unit:MonoBehaviour {

    //速度
    public float Speed=5;

    //移动
    public void Move(Vector2 dir)
    {
        transform.Translate(dir * Speed * Time.deltaTime);
    }

    //射击
    public void Shot()
    {
        Debug.Log("Shoot!!!");
    }
}

Player:继承自Unit,这里没有定义任何额外的操作。引入的目的只是为了表明,我们可以通过执行命令进行任何单位的基本操作。

public class Player : Unit
{

}

Command:命令接口,里面定义了执行和撤销方法。

public interface Command  {
    //执行
    void Excute();
    //撤销
    void Undo();
}

CmdMove:移动命令,实现Command接口,构造时传递命令所需参数。

public class CmdMove : Command {

    //单位
    Unit unit;
    //方向
    Vector2 dir;

    public CmdMove(Unit unit,Vector2 dir)
    {
        this.unit = unit;
        this.dir = dir;
    }

    public void Excute()
    {
        unit.Move(dir);
    }

    public void Undo()
    {
        unit.Move(-dir);
    }
}

CmdShoot:射击命令,实现Command接口,构造时传递所需参数。

public class CmdShoot : Command
{
    //单位
    Unit unit;

    public CmdShoot(Unit unit)
    {
        this.unit = unit;
    }

    public void Excute()
    {
        unit.Shot();
    }

    public void Undo()
    {
        Debug.Log("undo shoot!!!");
    }
}

注:就射击来讲,应该没有撤销操作可言,这里加入只是为了体现undo的调用。

InputManager:负责将输入以命令队列的形式执行。同时支持撤销操作。

public class InputManager : MonoBehaviour {

    //操作的对象
    public Player underControl;

    //待执行命令
    Queue<Command> nextCmd = new Queue<Command>();
    //已执行命令
    Stack<Command> preCmd = new Stack<Command>();

   
    private void Update()
    {
        GetCommand();
        //若命令队列存在命令,则取出执行
        if (nextCmd.Count > 0)
        {
            Command cmd = nextCmd.Dequeue();
            cmd.Excute();
            //放入已执行栈中
            preCmd.Push(cmd);
        }

        //撤销操作
        if (Input.GetKey(KeyCode.Z))
        {
            //防溢出
            if (preCmd.Count == 0)
            {
                Debug.Log("cmd is null");
                return;
            }               
            preCmd.Pop().Undo();
        }
    }

    //获取命令并存入队列
    void GetCommand()
    {
        float x = Input.GetAxis("Horizontal");
        float y = Input.GetAxis("Vertical");
        if (x != 0 || y != 0)
        {
            Command cmd = new CmdMove(underControl, new Vector2(x, y));
            nextCmd.Enqueue(cmd);
        }           
        if (Input.GetKeyDown(KeyCode.J))
        {
            Command cmd= new CmdShoot(underControl);
            nextCmd.Enqueue(cmd);
        }
    }
}

将InputManager挂载到场景任意物体。将Player挂载到玩家对象上,并赋给InputManager。运行即可。

这只是一个很简单的案例,但是已经可以充分发现命令模式带给我们的惊喜。

它使代码更加优雅、简洁。

这只是一个类似同步执行命令的例子。

想实现更加复杂的功能则需要在这基础之上拓展。

我一直是war3、刀塔的爱好者,这两个游戏中的shift操作一直是我认为比许多其他同类型游戏优异的地方。

而这种操作的实现,应该就是命令模式在异步状态下的表现。

猜你喜欢

转载自blog.csdn.net/a977621265/article/details/86750341