首先感谢《Game.Programming.Patterns(游戏编程模式)》一书,让我对设计模式有了更加全面的理解。

因为书中都是C语言的示例,无奈对C又知之甚少,在此就个人的理解,对书中命令模式章节的示例,尝试用C#写一下,如果有不恰当的地方还希望大家指出~~

先看一下菜鸟教程对命令模式的描述:

命令模式

实现:键盘输入触发角色行为

--> 键盘输入 --> 发出命令 --> 具体命令执行


定义角色行为命令:

//执行函数“Execute”参数:执行该行为的对象(角色)

//游戏行为基类, 根据需求是否继承MonoBehaviour
    public abstract class Command
    {
        public abstract void Execute(Actor actor);
    }

    //具体行为子类
    public class FireCommand : Command
    {
        public override void Execute(Actor actor)
        {
            if (actor == null)
                return;
            actor.Fire();
        }
    }

    //具体行为子类
    public class JumpCommand : Command
    {
        public override void Execute(Actor actor)
        {
            if (actor == null)
                return;
            actor.Jump();
        }
    }

//撤销。将每一次单独保存,撤销时还原到上一个行为即可。

//多步撤销,用Stack或List依次保存每次行为,撤销时还原到上一个行为,同时删除当前及以后的行为。

//(另,关于数据结构,Move行为只是为了演示利用命令模式实现撤销操作,使用时还是要考虑实际情况。比如只是撤销角色位置移动,可以把位置信息Vector3用一个Stack或List记录下来,撤销时取上一个位置信息给角色赋值,如果撤销的操作比较多,既有角色位置信息,还有HP、MP等等,这时候就需要用类来记录完整的角色信息了)

    public class MoveCommand : Command
    {
        Vector3 targetPos;
        Vector3 beforePos;

        public MoveCommand(Vector3 moveToPos)
        {
            targetPos = moveToPos;
            beforePos = Vector3.zero;
        }

        public override void Execute(Actor actor)
        {
            if (actor == null)
                return;
            //保存移动之前的位置
            beforePos = actor.position;
            actor.MoveTo(targetPos);
        }

        public void MoveBack(Actor actor)
        {
            actor.MoveTo(beforePos);
        }
    }

定义角色及具体行为表现:

//通过行为命令调用角色函数,再执行具体对象的具体行为

public class Actor
    {
        public Vector3 position { get; protected set; }

        public virtual void Jump()
        {
            Debug.Log(GetType().Name + "  Jump");
        }

        public virtual void Fire()
        {
            Debug.Log(GetType().Name + "  Fire");
        }

        public virtual void MoveTo(Vector3 targetPos)
        {
            position = targetPos;
            Debug.Log(GetType().Name + "  Move To  " + targetPos);
        }

    }

    public class Player01 : Actor
    {

    }
    public class Player02 : Actor
    {

    }

按键输入,触发行为:

//自定义按键事件:定义按键(指针),在"InputConfig"函数中,给按键绑定行为(方法),这样在按键输入以后,会自动调用自定义绑定的行为。

//控制多角色,可以随时切换角色,触发当前选择角色的行为

public class InputHandler : MonoBehaviour
    {
        //可控制角色
        Actor actor01 = new Player01();
        Actor actor02 = new Player02();
        //当前控制角色
        Actor currentActor;

        //输入按键定义调用函数(命令)
        Command inputF;
        Command inputJ;

        void Start()
        {
            //默认角色
            currentActor = actor01;
            //配置输入按键
            InputConfig();
        }

        //玩家自定义按键功能: 输入按键 与 执行命令 分开, 
        void InputConfig()
        {
            //自定义绑定命令函数
            inputF = new FireCommand();
            inputJ = new JumpCommand();
        }

        void Update()
        {
            //输入处理
            if (Input.GetKeyDown(KeyCode.F))
                inputF.Execute(currentActor);
            else if(Input.GetKeyDown(KeyCode.J))
                inputJ.Execute(currentActor);

            //移动
            if (Input.GetKeyDown(KeyCode.UpArrow))
                new MoveCommand(Vector3.up).Execute(currentActor);
            else if (Input.GetKeyDown(KeyCode.DownArrow))
                new MoveCommand(Vector3.down).Execute(currentActor);
            //······

            //切换控制角色
            if (Input.GetKeyDown(KeyCode.Alpha1))
                currentActor = actor01;
            else if (Input.GetKeyDown(KeyCode.Alpha2))
                currentActor = actor02;
        }
    }