IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> Unity开发数字孪生编辑器操作与Undo设计 -> 正文阅读

[开发工具]Unity开发数字孪生编辑器操作与Undo设计

Undo的程序设计基于以下想法:

一、所有对象从根本上来讲都是以由基本的数据类型组成的,包括int、float、bool、string等等。

二、undo从根本上是将上述基本类型的值设置回操作之前的值。

三、每次一操作都是对某些特定对象的属性修改,undo的作用是将这些属性设置为修改之前的值。

四、对象的每个属性都通过事件驱动具体的内容。

下面是一个UndoManager类,该类里面包含了一个undo操作List,而List的每一项都是一个UnityAction堆栈。

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class UndoManager : MonoBehaviour
{
	static public UndoManager instance;

	void Awake()
	{
		instance = this;
	}

	void Update()
	{
		if(Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))
		{
			if (Input.GetKeyDown(KeyCode.Z))
			{
				Undo();
			}
		}

		if(Input.GetMouseButtonUp(2)) Undo();
	}

	int undoLimit = 5;
	public void SetUndoLimit(int undoLimit) { this.undoLimit = undoLimit; }

	List<Stack<UnityAction>> listUndoOperation = new List<Stack<UnityAction>>();
	Stack<UnityAction> curUndoOperation = null;
	public void FinishCurrentOperation()
	{
		if (curUndoOperation == null) return;
		listUndoOperation.Add(curUndoOperation);
		while (listUndoOperation.Count > undoLimit)
		{
			listUndoOperation.RemoveAt(0);
		}
		curUndoOperation = null;
	}

	public void AddUndoAct(UnityAction act)
	{
		if (curUndoOperation == null)
		{
			curUndoOperation = new Stack<UnityAction>();
		}
		curUndoOperation.Push(act);
	}

	UnityAction onUndoEmpty;
	public void AddActUndoEmpty(UnityAction act) { onUndoEmpty -= act; onUndoEmpty += act; }
	public void RemoveActUndoEmpty(UnityAction act) { onUndoEmpty -= act; }
	public void Undo()
	{
		if (listUndoOperation.Count > 0)
		{
			int index = listUndoOperation.Count - 1;
			Stack<UnityAction> op = listUndoOperation[index];
			if (op != null)
			{
				while(op.Count > 0)
				{
					op.Pop()?.Invoke();
				}
			}
			listUndoOperation.RemoveAt(index);
		}
		else
		{
			onUndoEmpty?.Invoke();
		}
	}
}

一个Vector3驱动对象,这个对象用于驱动类似Tranform的position之类的内容。为了编程方面,里面添加了一些隐式转换,加减法操作等内容。

using UnityEngine;
using UnityEngine.Events;

public class ActVector3
{
	public ActVector3(Vector3 val, UnityAction<Vector3> onChangeVal)
	{
		v = val;
		this.onChangeVal = onChangeVal;
	}

	UnityAction<Vector3> onChangeVal;
	public void AddActChangeVal(UnityAction<Vector3> act) { onChangeVal -= act; onChangeVal += act; }
	public void RemoveActChangeVal(UnityAction<Vector3> act) { onChangeVal -= act; }

	bool addUndoEnable = true;

	Vector3 v;
	public Vector3 val
	{
		get
		{
			return v;
		}
		set
		{
			Vector3 vPre = v;
			v = value;
			if (v != vPre) onChangeVal(v);
			//
			if (addUndoEnable)
			{
				UndoManager.instance.AddUndoAct(() =>
				{
					addUndoEnable = false;
					val = vPre;
					addUndoEnable = true;
				});
			}
		}
	}

	public static implicit operator Vector3(ActVector3 actVector3)
	{
		return actVector3.val;
	}

	public static implicit operator ActVector3(Vector3 vector3)
	{
		return new ActVector3(vector3, null);
	}

	public static ActVector3 operator +(ActVector3 actVector3, Vector3 vector3)
	{
		actVector3.val += vector3;
		return actVector3;
	}

	public static ActVector3 operator +(Vector3 vector3, ActVector3 actVector3)
	{
		return actVector3 + vector3;
	}

	public static ActVector3 operator -(ActVector3 actVector3, Vector3 vector3)
	{
		actVector3.val -= vector3;
		return actVector3;
	}

	public static ActVector3 operator -(Vector3 vector3, ActVector3 actVector3)
	{
		return vector3 - actVector3.val;
	}
}

为了验证上述内容的可行性,这是一个使用案例。

using System.Collections;
using UnityEngine;

public class OpTest : MonoBehaviour
{
	[SerializeField]
	Transform tran;

	ActVector3 actPosition;
	void Start()
	{
		if (tran)
		{
			actPosition = new ActVector3(transform.position, (val) => { tran.position = val; });
			StartCoroutine(ChangePos());
		}
	}

	IEnumerator ChangePos()
	{
		yield return new WaitForSeconds(1);
		actPosition += Vector3.left;
		actPosition += Vector3.left;
		actPosition += Vector3.left;
		UndoManager.instance.FinishCurrentOperation();
		yield return new WaitForSeconds(1);
		actPosition += Vector3.up;
		actPosition += Vector3.up;
		actPosition += Vector3.up;
		actPosition += Vector3.up;
		UndoManager.instance.FinishCurrentOperation();
		yield return new WaitForSeconds(1);
		actPosition += Vector3.forward;
		actPosition += Vector3.forward;
		UndoManager.instance.FinishCurrentOperation();
		yield return new WaitForSeconds(1);
		actPosition += Vector3.right;
		actPosition += Vector3.right;
		actPosition += Vector3.right;
		UndoManager.instance.FinishCurrentOperation();
		yield return new WaitForSeconds(1);
		actPosition += Vector3.down;
		actPosition += Vector3.down;
		actPosition += Vector3.down;
		actPosition += Vector3.down;
		UndoManager.instance.FinishCurrentOperation();
		yield return new WaitForSeconds(1);
		actPosition += Vector3.back;
		actPosition += Vector3.back;
		UndoManager.instance.FinishCurrentOperation();
	}
}

基于上述脚本对物体状态进行改变之后,可以按下鼠标中键或者Ctrl+Z来执行Undo。

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2022-05-14 10:07:34  更:2022-05-14 10:08:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:46:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码