欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Unity常用命令模式详解

程序员文章站 2022-06-30 11:12:58
在调用一些简单的方法实现一系列的动作时,回退的问题比较重要。作为一款用户体验良好的产品而言,有回退功能将显得比较人性化,想想如果我们常用的window,在删除一个文件后无法...

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

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

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

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

Unity常用命令模式详解

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

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

Unity常用命令模式详解

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

Unity常用命令模式详解

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

Unity常用命令模式详解

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

Unity常用命令模式详解

其中用于保存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();
  }
}

仅供参考,谢谢阅读。

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