Unity3D撤回命令开发详解

本文实例为大家分享了Unity3D撤回命令功能开发,供大家参考,具体内容如下

在类似操作考核的项目中我们经常会遇到回到上一步的需求。所以我们有必要对每一个状态点的所有参与交互的物体的状态进行记录。好了,下面就是代码的实现:

首先肯定要创建命令的基类,

public class BaseCommand
{

 //执行命令
 public virtual void ExcuteCommand() { }

 //撤销命令
 public virtual void RevocationCommand() { }

}

因为我们控制物体的类似移动改变方式不同,有可能是直接移动的,有可能是用的dotween来操作移动,所以我们的执行命令函数可能对于我们没有实现的必要。下面我们要创建一个用来管理命令的脚本,供我们添加和移除命令,同时这个脚本我们给设置为单例,可供全局调用。如下:

public class CommandManager : MonoBehaviour
{
 public static CommandManager Instance = null;
 //管理命令
 private Stack<BaseCommand> commandStack = new Stack<BaseCommand>();

 private void Awake()
 {
  Instance = this;
 }

 //增加命令
 public void AddCommand(BaseCommand baseCommand)
 {
  commandStack.Push(baseCommand);
 }

 //移除命令 并且撤销一步操作
 public void RemoveCommand()
 {
  if(commandStack.Count>0)
  {
   BaseCommand baseCommand = commandStack.Pop();
   baseCommand.RevocationCommand();
  }
 }
}

有个命令基类,有了管理类,下面我们就要对不同命令进行专门的功能实现了。

一.移动类命令

//保存模型的位置 角度 大小信息
public class TransformCommand : BaseCommand
{
 private Transform target;
 private Vector3 pos;
 private Vector3 rota;
 private Vector3 scale;
 private Transform parent;
//我们在构造函数里直接传进来我们改变状态前的Transform信息
 public TransformCommand(Transform target, Vector3 pos, Vector3 rota, Vector3 scale,Transform parent)
 {
  this.target = target;
  this.pos = pos;
  this.rota = rota;
  this.scale = scale;
  this.parent = parent;
 }

 public override void ExcuteCommand()
 {
  base.ExcuteCommand();
 }

 public override void RevocationCommand()
 {
  target.SetParent(parent);
  target.transform.localPosition = pos;
  target.transform.localEulerAngles = rota;
  target.transform.localScale = scale;
 }
}

下面是我们写的测试脚本挂在到摄像头上,

public class CameraMove : MonoBehaviour {

 // Update is called once per frame
 void Update ()
 {
  if(Input.GetKeyDown(KeyCode.W))
  {
   TransformCommand cmd = new TransformCommand(transform,transform.localPosition,
    transform.localEulerAngles,transform.localScale,null);
   CommandManager.Instance.AddCommand(cmd);
   transform.Translate(Vector3.forward,Space.Self);
  }
 }
}

还需要写一个输入的类来调用撤退命令,代码如下:

public class Test : MonoBehaviour {

 private void Update()
 {
  if(Input.GetKeyDown(KeyCode.Escape))
  {
   CommandManager.Instance.RemoveCommand();
  }
 }
}

二.UI类用户控制改变状态

下面以InputField为例,介绍UI交互类的撤退命令,这个要比普通的麻烦一些。我找了官方文档好久也没发现值改变前得回掉函数,所以只能自己来实现了。首先我们要自己写一个脚本用来记录改变之前的值。挂载在场景里的InputField上。代码如下:

public class MyInputField : MonoBehaviour,IPointerClickHandler
{
 private InputField input;
 private string preString;//用来记录改变前得值

 private bool IsValueChange = false;//判断值是否发生改变

 private bool IsClick = false;//用来判断InputField是否被选中交互

 private void Awake()
 {
  input = GetComponent<InputField>();
  input.onValueChanged.AddListener(delegate { IsValueChange=true; });
  input.onEndEdit.AddListener(OnEndEditCallBck);
 }

 //结束编辑得回调函数
 void OnEndEditCallBck(string content)
 {
  IsClick = false;
  //如果值没变 直接返回 没必要增加命令
  if (IsValueChange == false) return;
  InputFieldCommand cmd = new InputFieldCommand(input,preString);
  CommandManager.Instance.AddCommand(cmd);
 }

 //当被点击时,我们的UI组件被交互 有被更改值得可能 所以要记录当前值
 public void OnPointerClick(PointerEventData eventData)
 {
  Debug.Log("点击");
  if (IsClick) return;
  preString = input.text;
  IsClick = true;
 }
}
public class InputFieldCommand : BaseCommand
{
 private InputField targetInput;
 private string content;

 public InputFieldCommand(InputField inputField,string content)
 {
  this.targetInput = inputField;
  this.content = content;
 }

 public override void RevocationCommand()
 {
  base.RevocationCommand();
  targetInput.text = content;
 }
}

上面就是在用户对InputField输入内容改变时自动记录上一步得命令。对于其他得UI组件类似Toggle Slider同样适用。

三.销毁生成的物体

我们在当前一步实例化很多物体,返回上一步就需要销毁所有实例化的物体。这里我们不建议直接销毁,而是利用对象池技术进行回收,还节约性能。对象池技术博客地址:点击打开链接  代码如下:

public class DestoryCommand : BaseCommand
{
 private List<GameObject> objects;

 public DestoryCommand(List<GameObject> objects)
 {
  this.objects = objects;
 }

 public override void RevocationCommand()
 {
  for(int i=0;i< objects.Count;i++)
  {
   //利用对象池技术回收物体 这里就不写了 因为还要把对象池的脚本添加进来
  }
 }
}

这个命令是在我们实例化物体后才能增加。其实就是把实例化的物体加入到List数组然后传入一个新声明的DestoryCommand构造函数中。以上效果图如下:

希望本博客对你有帮助!

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

(0)

相关推荐

  • Unity常用命令模式详解

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

  • Unity3D撤回命令开发详解

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

  • 深入浅出webpack教程系列_安装与基本打包用法和命令参数详解

    webpack,我想大家应该都知道或者听过,Webpack是前端一个工具,可以让各个模块进行加载,预处理,再进行打包.现代的前端开发很多环境都依赖webpack构建,比如vue官方就推荐使用webpack.废话不多说,我们赶紧开始吧. 第一步.安装webpack 新建文件夹webpack->再在webpack下面新建demo->命令行切换到demo目录,使用npm init --yes 初始化项目的package.json文件,然后执行npm install webpack --save-de

  • Mysql导入导出工具Mysqldump和Source命令用法详解

    在PHP网站开发中,时常遇到Mysql数据库备份或数据库迁移工作,这时Mysql怎么导入导出数据库中的数据就非常关键,Mysql本身提供了命令行导出工具Mysqldump和Mysql Source导入命令进行SQL数据导入导出工作,通过Mysql命令行导出工具Mysqldump命令能够将Mysql数据导出为文本格式(txt)的SQL文件,通过Mysql Source命令能够将SQL文件导入Mysql数据库中,下面通过Mysql导入导出SQL实例详解Mysqldump和Source命令的用法. M

  • Apifox Echo学习curl httpie 命令使用详解

    目录 正文 curl curl --request curl --head curl --include curl --verbose curl --location httpie && examples 结束 正文 curl,用于发送请求的命令行工具,一个 HTTP 请求客户端(实际上它也可以做 FTP/SCP/TELNET 协议的事情,可类比于浏览器中的 fetch. curl 是最为流行的 HTTP 请求命令行工具,在谷歌浏览器控制台的网络面板中,可将当前请求转化为 curl. 在学

  • 基于Unity3D实现仿真时钟详解

    目录 一.前言 二.时钟小工具开发 2-1.搭建UI 2-2.实现脚本 一.前言 今天实现一个时钟工具,其实在之前已经完成了一个简单的时钟工具:[Unity3D应用案例系列]时钟.钟表小组件开发. 那么,今天的这个小工具跟之前的有啥区别呢? 之前的时钟,是模拟真实时间时针分针秒针的旋转,比如: 可以当个时钟看. 二.时钟小工具开发 今天实现一个可以设置旋转到指定的时间下的表盘,简单说就是时钟定时. 2-1.搭建UI 新建一个Image,命名为Image_Clock(名字随意),作为时针和分针的父

  • bat批处理 if 命令示例详解

    if 命令示例详解 if,正如它E文中的意思,就是"如果"的意思,用来进行条件判断.翻译过来的意思就是:如果符合某一条件,便执行后面的命令. 主要用来判断,1.两个"字符串"是否相等:2.两个数值是大于.小于.等于,然后执行相应的命令. 当然还有特殊用法,如结合errorlevel:if errorlevel 1 echo error 或者结合defined(定义的意思):if defined test (echo It is defined) else echo 

  • Linux上的文件搜索命令实例详解

    locate 基础了解 在centos7上默认没有locate命令,需要先手动安装.安装步骤:http://www.cnblogs.com/feanmy/p/7676717.html locate命令搜索的后台数据库路径:/var/lib/mlocate/mlocate.db ls -hl /var/lib/mlocate total 1.2M -rw-r----- 1 root slocate 1.2M Oct 16 14:36 mlocate.db 更新数据库使用updatedb,配置文件为

  • Linux 中常用的Rpm命令实例详解

    rpm命令是RPM软件包的管理工具.rpm原本是Red Hat Linux发行版专门用来管理Linux各项套件的程序,由于它遵循GPL规则且功能强大方便,因而广受欢迎.逐渐受到其他发行版的采用.RPM套件管理方式的出现,让Linux易于安装,升级,间接提升了Linux的适用度. 语法 rpm(选项)(参数) 选项 -a:查询所有套件: -b<完成阶段><套件档>+或-t <完成阶段><套件档>+:设置包装套件的完成阶段,并指定套件档的文件名称: -c:只列出

  • Linux ftp 命令行中下载文件get与上传文件put的命令应用详解

    介绍:从本地以用户anok登录的机器192.168.0.16上通过ftp远程登录到192.168.0.6的ftp服务器上,登录用户名是peo.以下为使用该连接做的实验. 查看远程ftp服务器上用户peo相应目录下的文件所使用的命令为:ls,登录到ftp后在ftp命令提示符下查看本地机器用户anok相应目录下文件的命令是:!ls.查询ftp命令可在提示符下输入:?,然后回车. 1.从远程ftp服务器下载文件的命令格式: get  远程ftp服务器上当前目录下要下载的文件名  [下载到本地机器上当前

  • Hadoop 中 HBase Shell命令的详解

    Hadoop 中 HBase Shell命令的详解 HBase包含可以与HBase进行通信的Shell. HBase使用Hadoop文件系统来存储数据.所有这些任务发生在HDFS.下面给出的是一些由 常用的HBase Shell命令. 数据操纵语言 命令 说明 命令表达式 create 创建一个表 create '表名称', '列名称1','列名称2','列名称N' put  添加记录 put '表名称', '行名称', '列名称:', '值' get  查看记录 get '表名称', '行名称

随机推荐