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。

原文地址:https://www.cnblogs.com/Fflyqaq/p/11722396.html