Unity常用命令模式详解

在调用一些简单的方法实现一系列的动作时,回退的问题比较重要。作为一款用户体验良好的产品而言,有回退功能将显得比较人性化,想想如果我们常用的window,在删除一个文件后无法恢复将变得多么的糟糕。更为直观的例子是在玩一些小游戏时,比如象棋、推箱子,提供了悔棋的功能,用户有了更多选择的余地。

本文主要将的将是在Unity中实现一个以常听说的命令模式为设计原理,实现一个可以撤销移动、旋转、颜色和文字信息的小Demo。

命令模式,主要成员有提出要求的客户、设置命令的收集者、执行命令的接收者。客户要求很简单,点击按扭就要实现一项目具体的效果,设置命令的收集者无需要知道命令如何执行,只需要为执行者做好配制。用命令的执行者将执行一个方法,所有的命令者是继承于有这个方法的接口的类。

抽象到程序代码中,这三类成员分别对应于界面上的用户,RemoteControl (这里是随便命名的),RemoteLoader

先制作如上的界面,方便你比较直观的认识,其中左边两个是用于切换选择不同的命令。下面第一个按扭可以执行选中的命令,第二个按扭可以进行撤销操作。

程序,UGUI面局如下,在Canvas下分别设置了执行者和配制者。

制作好界面之后就可以来实现具体的脚本编辑了,分别创建好接口ICommand,配制脚本RemoteLoader和执行脚本RemoteControl,结构如下:

在Commonds中,分别编写了用于移动,旋转,颜色,文字的脚本

这样一来,就可以实现一个可撤销的命令模式了,效果如下所示:

其中用于保存undo方法和具体怎么undo都是使用Stack来实现的,下面分别是部分代码实现 :

一、接口

public interface ICommand
{
  void Execute();
  void UnDo();
}

二、执行器

public class RemoteControl : MonoBehaviour {
  public Button ctrlBtn;
  public Button undoBtn;
  public Text ctrlName;
  private ICommand icommand;

  public Stack<UnityAction> undoFunctions = new Stack<UnityAction>();

  void Awake(){
    ctrlBtn.onClick.AddListener(OnCtrlBtnClicked);
    undoBtn.onClick.AddListener(OnUnDoBtnClicked);
  }

  public void SetText(string textinfo)
  {
    ctrlName.text = textinfo;
  }

  public void SetCommond(ICommand icommand)
  {
    this.icommand = icommand;
  }

  /// <summary>
  /// 执行
  /// </summary>
  public void OnCtrlBtnClicked()
  {
    if (icommand != null)
    {
      icommand.Execute();
      undoFunctions.Push(icommand.UnDo);
    }
  }

  /// <summary>
  /// 撤销
  /// </summary>
  private void OnUnDoBtnClicked()
  {
    if (undoFunctions.Count > 0)
    {
      undoFunctions.Pop().Invoke();
    }
  }
}

三、配制加载器

public class RemoteLoader : MonoBehaviour
{
  public Button lastBtn;
  public Button nextBtn;

  private int index;
  private const int NUM_COMMAND = 10;
  private ICommand[] commands;
  private string[] textinfos;

  private MoveCommand movexCmd;
  private MoveCommand moveyCmd;
  private MoveCommand movezCmd;
  private RotateCommand rotxCmd;
  private RotateCommand rotyCmd;
  private RotateCommand rotzCmd;
  private ColorChangeCommand redColorCmd;
  private ColorChangeCommand greenColorCmd;
  private ColorChangeCommand blueColorCmd;
  private TextChangeCommand textCmd;

  private string[] infos = { "A","B", "C", "D", "E", "F" };
  public RemoteControl remoteCtrl;

  public GameObject cube;

  void Awake()
  {
    lastBtn.onClick.AddListener(OnLastBtnClicked);
    nextBtn.onClick.AddListener(OnNextBtnClicked);
  }

  void Start()
  {
    commands = new ICommand[NUM_COMMAND];
    textinfos = new string[NUM_COMMAND];

    textinfos[0] = "x方向移动";
    commands[0] = new MoveCommand(cube.transform, Vector3.right);
    textinfos[1] = "y方向移动";
    commands[1] = new MoveCommand(cube.transform, Vector3.up);
    textinfos[2] = "z方向移动";
    commands[2] = new MoveCommand(cube.transform, Vector3.forward);

    textinfos[3] = "x轴旋转10度";
    commands[3] = new RotateCommand(cube.transform, Vector3.right * 10);
    textinfos[4] = "y轴旋转10度";
    commands[4] = new RotateCommand(cube.transform, Vector3.up * 10);
    textinfos[5] = "z轴旋转10度";
    commands[5] = new RotateCommand(cube.transform, Vector3.forward * 10);

    textinfos[6] = "变红";
    commands[6] = new ColorChangeCommand(Color.red, cube.GetComponent<Renderer>().material);
    textinfos[7] = "变绿";
    commands[7] = new ColorChangeCommand(Color.green, cube.GetComponent<Renderer>().material);
    textinfos[8] = "变蓝";
    commands[8] = new ColorChangeCommand(Color.blue, cube.GetComponent<Renderer>().material);
    textinfos[9] = "换信息";
    commands[9] = new TextChangeCommand(cube.GetComponentInChildren<TextMesh>(), infos);
  }

  private void OnNextBtnClicked()
  {
    if (index == NUM_COMMAND || index == -1)
    {
      index = 0;
    }

    remoteCtrl.SetCommond(commands[index]);
    remoteCtrl.SetText(textinfos[index]);
    index++;
  }

  private void OnLastBtnClicked()
  {
    if (index == NUM_COMMAND || index == -1)
    {
      index = NUM_COMMAND - 1;
    }

    remoteCtrl.SetCommond(commands[index]);
    remoteCtrl.SetText(textinfos[index]);
    index--;
  }

}

四、颜色转换命令脚本

public class ColorChangeCommand : ICommand
{
  private Stack<Color> m_OriginColor = new Stack<Color>();
  private Color m_Color;
  private Material m_Material;

  public ColorChangeCommand(Color color, Material material)
  {
    m_Color = color;
    m_Material = material;
  }

  public void Execute()
  {
    m_OriginColor.Push(m_Material.color);
    m_Material.color = m_Color;
  }

  public void UnDo()
  {
    m_Material.color = m_OriginColor.Pop();
  }
}

五、移动命令脚本

public class MoveCommand : ICommand
{
  private Vector3 m_Offset;
  private Transform m_Object;

  public MoveCommand(Transform obj, Vector3 offset)
  {
    this.m_Object = obj;
    this.m_Offset = offset;
  }

  public void Execute()
  {
    m_Object.transform.position += m_Offset;
  }

  public void UnDo()
  {
    m_Object.transform.position -= m_Offset;
  }
}

六、转换命令脚本

public class RemoteControl : MonoBehaviour {
  public Button ctrlBtn;
  public Button undoBtn;
  public Text ctrlName;
  private ICommand icommand;

  public Stack<UnityAction> undoFunctions = new Stack<UnityAction>();

  void Awake(){
    ctrlBtn.onClick.AddListener(OnCtrlBtnClicked);
    undoBtn.onClick.AddListener(OnUnDoBtnClicked);
  }

  public void SetText(string textinfo)
  {
    ctrlName.text = textinfo;
  }

  public void SetCommond(ICommand icommand)
  {
    this.icommand = icommand;
  }

  /// <summary>
  /// 执行
  /// </summary>
  public void OnCtrlBtnClicked()
  {
    if (icommand != null)
    {
      icommand.Execute();
      undoFunctions.Push(icommand.UnDo);
    }
  }

  /// <summary>
  /// 撤销
  /// </summary>
  private void OnUnDoBtnClicked()
  {
    if (undoFunctions.Count > 0)
    {
      undoFunctions.Pop().Invoke();
    }
  }
}

七、文字加载脚本

public class TextChangeCommand : ICommand
{
  private Stack<string> lastInfos = new Stack<string>();
  private IEnumerator<string> datas;
  private TextMesh m_Textmesh;

  public TextChangeCommand(TextMesh textMesh,ICollection<string> texts)
  {
    datas = texts.GetEnumerator();
    m_Textmesh = textMesh;
  }

  public void Execute()
  {
    if (!datas.MoveNext())
    {
      datas.Reset();
      datas.MoveNext();
    }
    lastInfos.Push(m_Textmesh.text);
    m_Textmesh.text = datas.Current;
  }

  public void UnDo()
  {
    m_Textmesh.text = lastInfos.Pop();
  }
}

仅供参考,谢谢阅读。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Unity3D撤回命令开发详解

    本文实例为大家分享了Unity3D撤回命令功能开发,供大家参考,具体内容如下 在类似操作考核的项目中我们经常会遇到回到上一步的需求.所以我们有必要对每一个状态点的所有参与交互的物体的状态进行记录.好了,下面就是代码的实现: 首先肯定要创建命令的基类, public class BaseCommand { //执行命令 public virtual void ExcuteCommand() { } //撤销命令 public virtual void RevocationCommand() { }

  • Unity常用命令模式详解

    在调用一些简单的方法实现一系列的动作时,回退的问题比较重要.作为一款用户体验良好的产品而言,有回退功能将显得比较人性化,想想如果我们常用的window,在删除一个文件后无法恢复将变得多么的糟糕.更为直观的例子是在玩一些小游戏时,比如象棋.推箱子,提供了悔棋的功能,用户有了更多选择的余地. 本文主要将的将是在Unity中实现一个以常听说的命令模式为设计原理,实现一个可以撤销移动.旋转.颜色和文字信息的小Demo. 命令模式,主要成员有提出要求的客户.设置命令的收集者.执行命令的接收者.客户要求很简

  • linux下防火墙开启某个端口号及防火墙常用命令使用(详解)

    1.永久性生效,重启后不会复原 开启:chkconfigiptables on 关闭:chkconfigiptables off 2.即时生效,重启后复原 重启防火墙 方式一:/etc/init.d/iptables restart 方式二:service iptables restart 关闭防火墙: 方式一:/etc/init.d/iptables stop 方式二:service iptables stop 启动防火墙 方式一:/etc/init.d/iptables start 方式二:

  • Java设计模式之命令模式详解

    命令模式 定义:将请求封装成对象,这可以让你使用不同的请求.队列.或者日志来参数化其他对象. 何时使用命令模式?当需要将发出请求的对象和执行请求的对象解耦的时候,使用命令模式. 在被解耦的两者之间是通过命令对象进行沟通的.命令对象封装了接收者和一个或一组动作. 调用者通过调用命令对象的execute()方法发出请求,这会使接收者的动作被调用. 调用者可以接收命令当作参数,甚至在运行时动态地进行. 优点: 1.降低了系统耦合度. 2.新的命令可以很容易添加到系统中去. 缺点:使用命令模式可能会导致

  • Docker常用命令Study03详解

    一. 帮助命令 1. 查看当前docker版本 docker version 2. 显示 Docker 系统信息,包括镜像和容器数 docker info 3. 查看帮助文档,类似于CentOS的Man命令 docker --help 二. 镜像命令 1. 查看本地主机上的镜像: #列出本地所有的镜像(含中间映像层) docker images -a #只显示镜像ID docker images -q #显示完整的镜像信息 docker images --no-trunc 2.搜索镜像:http

  • 深入理解JavaScript系列(34):设计模式之命令模式详解

    介绍 命令模式(Command)的定义是:用于将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或者记录请求日志,以及执行可撤销的操作.也就是说改模式旨在将函数的调用.请求和操作封装成一个单一的对象,然后对这个对象进行一系列的处理.此外,可以通过调用实现具体函数的对象来解耦命令对象与接收对象. 正文 我们来通过车辆购买程序来展示这个模式,首先定义车辆购买的具体操作类: 复制代码 代码如下: $(function () { var CarManager = { // 请求

  • Android编程设计模式之命令模式详解

    本文实例讲述了Android编程设计模式之命令模式.分享给大家供大家参考,具体如下: 一.介绍 命令模式(Command Pattern),是行为型设计模式之一.命令模式相对于其他的设计模式来说并没有那么多的条条框框,其实它不是一个很"规范"的模式,不过,就是基于这一点,命令模式相对于其他的设计模式更为灵活多变.我们接触比较多的命令模式个例无非就是程序菜单命令,如在操作系统中,我们点击"关机"命令,系统就会执行一系列的操作,如先是暂停处理事件,保存系统的一些配置,然

  • Maven是什么?Maven的概念+作用+仓库的介绍+常用命令的详解

    Maven系列1 1.什么是Maven? Maven是一个项目管理工具,它包含了一个对象模型.一组标准集合,一个依赖管理系统.和用来运行定义在生命周期阶段中插件目标和逻辑. 核心功能 Maven的核心功能是合理叙述项目间的依赖关系,通俗点 就是通过pom.xml文件的配置获取jar包不用手动的去添加jar包,,这个pom.xml包我后面会叙述,不过已经学习过maven的 人应该对这个很熟悉.其本质就是通过配置pom.xml来获取jar包,当然这是在该项目必须是maven项目的前提下.那么什么是m

  • Python画图常用命令大全(详解)

    matplotlib官网 matplotlib库默认英文字体 添加黑体('SimHei')为绘图字体 代码: plt.rcParams['font.sans-serif']=['SimHei'] 1. 简单例程柱状图 基本方法:matplotlib.pyplot.bar() 基本参数:bar(x,y) 其他参数:颜色color        宽度width        透明度alpha 其他方法:图例legend()        横轴定义xlable()        纵轴定义ylable(

  • Java设计模式之java命令模式详解

    目录 命令模式的介绍 角色 订单案例 命令模式的优点 适用场景 示例代码 应用 宏命令----执行一组命令 示例代码 总结 JDK源码解析 Runable是一个典型命令模式,Runnable担当命令的角色,Thread充当的是调用者,start方法就是其执行方法 总结 命令模式的介绍 命令模式是对命令的封装.命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象 每一个命令都是一个操作:请求的一方发出请求要求执行一个操作:接收的一方收到请求,并执行操作.命令模式允许请求的一方和接收的一

  • Linux常用命令mkdir详解

    mkdir  make directories  创建目录 语法格式:mkdir [option][directory] mkdir [选项] [目录] 注意:mkdir 命令以及后面的选项和目录,每个元之间都要至少要有一个空格 参数选项:-p,-m mkdir -p ysg/test 使用 mkdir 创建多级目录时,建议直接只用 -p 参数,可以避免出现 "No such file or directory" 没有文件或目录的报错了,也不会影响已存在的目录. mkdir -m 77

随机推荐