游戏编程模式(Game Programming Patterns)的 C#&Unity 练习一:命令模式

本人游戏策划一枚,开始学习一下游戏编程,以便于将来失业了可以做做独立游戏。

命令模式

核心描述:
将一个请求(request)封装成一个对象,从而允许你使用不同的请求,队列或者日志将客户端参数化,同时支持请求操作的撤销与恢复。

知识点:
1.将“输入指令 - 角色执行”添加一个中间层,改为“输入指令 - 指令对象 - 角色执行”。
2.实现撤销与恢复,将“指令对象”存储在字典中,用整型变量currentKey来指向当前处于字典中的具体指令。用整型变量lastKey和nextKey来指向上一次和下一次的具体指令。

实现流程:
1.在Unity中创建一个GameObject,用于循环监听按键事件和初始化ExecuteCommand类(执行指令的类);
2.创建一个CommandMode类作为指令的父类,以便于在撤销和恢复的时候,让子类以父类的身份存储到指令序列的字典中。
3.创建一个ExecuteCommand类,用来执行具体的指令,并将所有的指令用来存放到指令序列的字典中。

下面贴上源代码

CommandMode类

public class CommandMode {

    public CommandMode()
    { }

    /// <summary>
    /// 构造函数,子类可以继承
    /// </summary>
    /// <param name="gameObject">指令起作用的对象</param>
    protected CommandMode(GameObject gameObject)
    { }

    /// <summary>
    /// 执行向上移动,具体在子类中实现
    /// </summary>
    public virtual void MoveUp()
    { }

    /// <summary>
    /// 执行向下移动,具体在子类中实现
    /// </summary>
    public virtual void MoveDown()
    { }

    /// <summary>
    /// 执行向左移动,具体在子类中实现
    /// </summary>
    public virtual void MoveLeft()
    { }

    /// <summary>
    /// 执行向右移动,具体在子类中实现
    /// </summary>
    public virtual void MoveRight()
    { }


    /// <summary>
    /// 撤销指令,不同的指令类型撤销方式不同,所以需要在具体的指令子类中重写
    /// </summary>
    public virtual void UnDo()
    { }

    /// <summary>
    /// 恢复指令,不同的指令类型恢复方式不同,所以需要在具体的指令子类中重写
    /// </summary>
    public virtual void ReDo()
    { }
}

指令的类型有很多种,例如move,jump。不同的类型Undo和Redo的方法也不一样,所以需要把具体的类型用子类来重写
Move类


public class Move : CommandMode {
    GameObject gmObject;
    private float[] targetPos;
    private float[] currentPos;

    public float[] TargetPos
    {
        get { return targetPos;  }
        set { targetPos = value; }
    }

    public float[] CurrentPos
    {
        get { return currentPos; }
        set { currentPos = value; }
    }

    public GameObject GmObject
    {
        get { return gmObject; }
        set { gmObject = value; }
    }

    /// <summary>
    /// 构造函数初始化
    /// </summary>
    /// <param name="gameObject">指令要生效的对象</param>
    public Move(GameObject gameObject) : base(gameObject)
    {
        TargetPos = new float[3];
        CurrentPos = new float[3];
        GmObject = gameObject;
        CurrentPos[0] = GmObject.transform.position.x;
        CurrentPos[1] = GmObject.transform.position.y;
        CurrentPos[2] = GmObject.transform.position.z;
    }

    /// <summary>
    /// 向上移动
    /// </summary>
    public override void MoveUp()
    {
        TargetPos[0] = CurrentPos[0];
        TargetPos[1] = CurrentPos[1] + 0.5f;
        TargetPos[2] = CurrentPos[2];
        GmObject.transform.position = new Vector3(TargetPos[0], TargetPos[1], TargetPos[2]);
    }

    /// <summary>
    /// 向下移动
    /// </summary>
    public override void MoveDown()
    {
        TargetPos[0] = CurrentPos[0];
        TargetPos[1] = CurrentPos[1] - 0.5f;
        TargetPos[2] = CurrentPos[2];
        GmObject.transform.position = new Vector3(TargetPos[0], TargetPos[1], TargetPos[2]);
    }

    /// <summary>
    /// 向左移动
    /// </summary>
    public override void MoveLeft()
    {
        TargetPos[0] = CurrentPos[0] - 0.5f;
        TargetPos[1] = CurrentPos[1];
        TargetPos[2] = CurrentPos[2];
        GmObject.transform.position = new Vector3(TargetPos[0], TargetPos[1], TargetPos[2]);
    }

    /// <summary>
    /// 向右移动
    /// </summary>
    public override void MoveRight()
    {
        TargetPos[0] = CurrentPos[0] + 0.5f;
        TargetPos[1] = CurrentPos[1];
        TargetPos[2] = CurrentPos[2];
        GmObject.transform.position = new Vector3(TargetPos[0], TargetPos[1], TargetPos[2]);
    }

    /// <summary>
    /// 撤销指令
    /// </summary>
    public override void UnDo()
    {
        GmObject.transform.position = new Vector3(CurrentPos[0], CurrentPos[1], CurrentPos[2]);
    }

    /// <summary>
    /// 恢复指令
    /// </summary>
    public override void ReDo()
    {
        GmObject.transform.position = new Vector3(TargetPos[0], TargetPos[1], TargetPos[2]);
    }
}

指令的具体实现已经完成,现在需要一个类来执行按键检测并该指令。
ExecuteCommand类


public class ExecuteCommand{

    private GameObject gmObject;    //指令执行具体对象
    private CommandMode command;    //具体的指令
    private Dictionary<int, CommandMode> CommandDictionary; //存放指令的字典
    private int currentKey; //当前指令在字典中的索引
    private int lastKey;    //上一步指令在字典中的索引
    private int nextKey;    //下一步指令在字典中的索引

    /// <summary>
    /// 按键变量
    /// </summary>
    public KeyCode KeyW;
    public KeyCode KeyA;
    public KeyCode KeyS;
    public KeyCode KeyD;
    public KeyCode KeyZ;
    public KeyCode KeyY;


    /// <summary>
    /// 构造方法
    /// </summary>
    /// <param name="gameObject">指令生效的对象</param>
    public ExecuteCommand(GameObject gameObject)
    {
        gmObject = gameObject;
        CommandDictionary = new Dictionary<int, CommandMode>();
    }

    /// <summary>
    /// 执行方法,用来在Update中调用
    /// </summary>
    public void ExecuteUpdate()
    {
        if (Input.GetKeyDown(KeyW))
        {
            Up();
        }
        if (Input.GetKeyDown(KeyS))
        {
            Down();
        }
        if (Input.GetKeyDown(KeyA))
        {
            Left();
        }
        if (Input.GetKeyDown(KeyD))
        {
            Right();
        }
        if (Input.GetKeyDown(KeyZ))
        {
            CommandUnDo();
        }
        if (Input.GetKeyDown(KeyY))
        {
            CommandReDo();
        }
    }

    /// <summary>
    /// 使目标向上移动,
    /// </summary>
    public void Up()
    {
        command = new Move(gmObject);
        command.MoveUp();
        PutCommandInDic(command);
    }

    /// <summary>
    /// 使目标向下移动
    /// </summary>
    public void Down()
    {
        command = new Move(gmObject);
        command.MoveDown();
        PutCommandInDic(command);
    }

    /// <summary>
    /// 使得目标向左移动
    /// </summary>
    public void Left()
    {
        command = new Move(gmObject);
        command.MoveLeft();
        PutCommandInDic(command);
    }

    /// <summary>
    /// 使目标向右移动
    /// </summary>
    public void Right()
    {
        command = new Move(gmObject);
        command.MoveRight();
        PutCommandInDic(command);
    }

    /// <summary>
    /// 指令的撤销
    /// </summary>
    public void CommandUnDo()
    {
        //如果currentKey为第一个指令,则不允许撤销。否则取出上一次的指令索引,便于撤销。
        if (currentKey == 1)
        {
            return;
        }
        else
        {
            lastKey = currentKey - 1;
        }

        //用上一次的指令索引进行撤销
        CommandMode UndoCommand = new CommandMode();
        UndoCommand = CommandDictionary[lastKey];
        UndoCommand.UnDo();

        //撤销后,currentKey就应该等于新的
        currentKey = lastKey;

    }

    /// <summary>
    /// 指令的恢复
    /// </summary>
    public void CommandReDo()
    {
        //如果currentKey为最新的指令,则不允许重做。否则取出下一次的指令索引,便于重做。
        if (currentKey == CommandDictionary.Count)
        {
            return;
        }
        else
        {
            nextKey = currentKey + 1;
        }

        //用下一次的指令索引进行重做。
        CommandMode UndoCommand = new CommandMode();
        UndoCommand = CommandDictionary[nextKey];
        UndoCommand.ReDo();

        //重做后,更新currentKey为最新的索引。
        currentKey = nextKey;

    }

    /// <summary>
    /// 将指令存入到字典中
    /// </summary>
    /// <param name="commandMode">具体的指令,该参数的值实际上指令的子类以父类的身份出现的</param>
    private void PutCommandInDic(CommandMode commandMode)
    {
        //在指令序列中,把当前撤销/重做的指令后面的指令全部删除掉,用以记录新的指令序列。
        ArrayList keyArrayList = new ArrayList();
        foreach (int key in CommandDictionary.Keys)
        {
            if (key > currentKey)
            {
                keyArrayList.Add(key);
            }
        }
        foreach (int i in keyArrayList)
        {
            CommandDictionary.Remove(i);
        }

        //记录新的指令序列,设置currentKey为最新的指令的索引。
        CommandDictionary.Add(CommandDictionary.Count + 1, commandMode);
        currentKey = CommandDictionary.Count;
    }
}

接下来只需要在外部的Update中调用ExecuteUpdate(),并对KeyCode进行按键赋值即可。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天丛云索隆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值