zoukankan      html  css  js  c++  java
  • Unity---游戏设计模式(13)之命令模式




    概述参考请看 参考博客

    将一个请求封装为一个Command对象,从而使你可用不同的请求对客户进行参数化; 对请求排队或记录请求日志,以及支持可撤销的操作。

    比如RTS游戏中的基地升级功能。升级是需要时间的,当我们增加好几次升级时,它就会先等待第一次升级完成后才会执行后面的升级。
    如果我们此时想要减少升级次数也可以。
    我们就可以把每个升级之类的操作当作一个Command请求,每个请求需要排队执行,我们也可以撤销请求。

    1、命令模式原型

    命令模式原型UML图

    命令模式原型代码

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    /// <summary>
    /// 命令模式
    /// </summary>
    public class CommandMode : MonoBehaviour
    {
        private void Start()
        {
            CommandInvoker invoker = new CommandInvoker();
            ConcreteCommand1 cmd1 = new ConcreteCommand1(new Receiver1());
            ConcreteCommand1 cmd2 = new ConcreteCommand1(new Receiver1());
    
            invoker.AddCommand(cmd1);
            invoker.AddCommand(cmd2);
            invoker.ExecuteCommand();
    
        }
    }
    
    
    /// <summary>
    /// 命令管理类
    /// 根据invoker执行Command命令
    /// </summary>
    public class CommandInvoker
    {
        //命令集合
        private List<ICommand> mCommands = new List<ICommand>();
    
        public void AddCommand(ICommand command)
        {
            mCommands.Add(command);
        }
        /// <summary>
        /// 使用params参数一次添加多个命令
        /// </summary>
        public void AddCommand(params ICommand[] commands)
        {
            foreach (ICommand command in commands)
            {
                mCommands.Add(command);
            }
        }
    
        /// <summary>
        /// 执行所有命令,执行完并清除
        /// </summary>
        public void ExecuteCommand()
        {
            foreach (ICommand command in mCommands)
            {
                command.Execute();
            }
            mCommands.Clear();
        }
    }
    
    /// <summary>
    /// 抽象命令类
    /// </summary>
    public abstract class ICommand
    {
        public abstract void Execute();
    }
    public class ConcreteCommand1 : ICommand
    {
        //每个命令类中有一个接收者,接收者对象绑定一个具体的动作
        private Receiver1 mReceiver1;
    
        public ConcreteCommand1(Receiver1 receiver1)
        {
            mReceiver1 = receiver1;
        }
    
        //通过调用接收者来执行具体的命令
        public override void Execute()
        {
            mReceiver1.Action("ConcreteCommand1");
        }
    }
    
    /// <summary>
    /// 接收者类,绑定一个具体的执行操作,任何类都可能作为一个接收者
    /// </summary>
    public class Receiver1
    {
        public void Action(string cmd)
        {
            Debug.Log("Receiver1执行了命令:" + cmd);
        }
    }
    

    3、命令模式实例

    实例UML图
    GameSceneState场景类,和状态模式中的实例相接。请看状态模式(1)实例

    实例代码
    GameSceneState

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class GameSceneState : ISceneState
    {
        public GameSceneState(SceneStateController controller)
            : base("03GameScene", controller)
        {
        }
    
        private Button mUpgradeButton;
        private Button mCancelUpgradeButton;
    
        //当前等级表示兵营的当前等级
        //提升等级表示将要升级的次数
        //升级时间表示每升一级的时间,会一直减
        private Text mNowLevelTextNum;
        private Text mUpLevelTextNum;
        private Text mUpgradeTimeNum;
    
        private Home mHome;
    
        public override void EnterScene()
        {
            Init();
        }
        public override void UpdateScene()
        {
            UpdateHomeMessage();
            if (mHome != null)
            {
                mHome.Update();
            }
        }
    
        /// <summary>
        /// 初始化
        /// </summary>
        public void Init()
        {
            mUpgradeButton = GameObject.Find("UpgradeButton").GetComponent<Button>();
            mCancelUpgradeButton = GameObject.Find("CancelUpgradeButton").GetComponent<Button>();
            mNowLevelTextNum = GameObject.Find("NowLevelTextNum").GetComponent<Text>();
            mUpLevelTextNum = GameObject.Find("UpLevelTextNum").GetComponent<Text>();
            mUpgradeTimeNum = GameObject.Find("UpgradeTimeNum").GetComponent<Text>();
    
            mUpgradeButton.onClick.AddListener(HomeUpgrade);
            mCancelUpgradeButton.onClick.AddListener(CancelHomeUpgrade);
    
            mHome = new Home();
        }
    
        /// <summary>
        /// 基地升级
        /// </summary>
        public void HomeUpgrade()
        {
            mHome.AddCommand(new UpgradeHomeCommand());
        }
        /// <summary>
        /// 取消基地升级
        /// </summary>
        public void CancelHomeUpgrade()
        {
            mHome.RemoveCommand();
        }
    
        /// <summary>
        /// 更新基地显示信息
        /// </summary>
        public void UpdateHomeMessage()
        {
            mNowLevelTextNum.text = mHome.mNowLevel.ToString();
            mUpLevelTextNum.text = mHome.mUpLevel.ToString();
            mUpgradeTimeNum.text = mHome.mUpgradeTimer.ToString("0.00");
    
            //当正在升级为0,不能再点击取消升级按钮。
            if (mHome.mUpLevel == 0)
            {
                mCancelUpgradeButton.interactable = false;
            }
            else
            {
                mCancelUpgradeButton.interactable = true;
            }
        }
    }
    
    

    Home

    /// <summary>
    /// 基地类---相当于CommandInvoker
    /// </summary>
    public class Home
    {
        /// <summary>
        /// 命令集合
        /// </summary>
        private List<IHomeCommand> mHomeCommandList;
    
        public int mNowLevel = 0;
        public int mUpLevel = 0;
        public float mUpgradeTimer = 2;
        public float mUpgradeTime = 2;
    
        public Home()
        {
            mHomeCommandList = new List<IHomeCommand>();
        }
    
        /// <summary>
        /// 添加升级命令
        /// </summary>
        public void AddCommand(IHomeCommand command)
        {
            mHomeCommandList.Add(command);
            mUpLevel++;
        }
        /// <summary>
        /// 移除一个升级命令
        /// </summary>
        public void RemoveCommand()
        {
            mHomeCommandList.RemoveAt(mHomeCommandList.Count - 1);
            mUpLevel--;
            //如果提示等级为空,时间要重置
            if (mUpLevel == 0)
            {
                mUpgradeTimer = mUpgradeTime;
            }
        }
    
        public void Update()
        {
            UpdateHomeMessage();
        }
    
        /// <summary>
        /// 更新升级时间信息
        /// </summary>
        public void UpdateHomeMessage()
        {
            if (mUpLevel > 0)
            {
                if (mUpgradeTimer > 0)
                {
                    mUpgradeTimer -= Time.deltaTime;
                }
                else
                {
                    //成功升一级:执行一个命令,命令集合改变,显示改变
                    mHomeCommandList[0].Execute();
                    mHomeCommandList.RemoveAt(0);
    
                    mUpLevel--;
                    mNowLevel++;
                    mUpgradeTimer = mUpgradeTime;
                }
            }
        }
    }
    

    IHomeCommand

    /// <summary>
    /// 基地的命令---命令模式
    /// </summary>
    public abstract class IHomeCommand
    {
        public abstract void Execute();
    }
    

    UpgradeHomeCommand

    /// <summary>
    /// 基地升级命令
    /// </summary>
    public class UpgradeHomeCommand : IHomeCommand
    {
        public override void Execute()
        {
            Debug.Log("成功升1级");
        }
    }
    

    效果

    3、命令模式优缺点

    优点

    1. 降低了请求者和实现者之间的耦合度。
    2. 对请求排队或记录请求日志,支持撤销操作。
    3. 可以容易地设计一个组合命令。
    4. 新命令可以容易地加入到系统中。

    缺点

    1. 类个数较多

    4、新知识

    4.1 ToString()保留小数位

    float num = 1.30f;
    
    Console.WriteLine(num.ToString("#0.00")); 
    //输出1.30
    
    Console.WriteLine(decTemp.ToString("#.##"));
    //输出1.3
    

    使用第二种方式保留小数位时,#会自动去掉0。

  • 相关阅读:
    git clone SSL error解决
    day11_文件读写
    python练习day0120
    day12_文件读写_return
    GIS开发常用算法原理分析
    SoapToolkit3.0分发技术
    平台符合性审查测试工具安装教程
    MapX编程详解(C++)MapX发布技术
    Google地图定位偏移矫正
    串口通信编程多线程异步方式
  • 原文地址:https://www.cnblogs.com/Fflyqaq/p/11722396.html
Copyright © 2011-2022 走看看