Unity UndoRedo(撤销重做)功能
需求
撤销与重做功能
思考
关于记录的数据的两点思考:
- 记录操作
- 记录影响显示和逻辑的所有数据
很显然这里就要考虑取舍了:
记录操作 这种方案只需要记录每一步的操作,具体这个操作要怎么渲染和实现出来完全需要自己去实现,这种方式的好处是记录的数据量比较小,节省内存,但业务逻辑复杂,适合复杂庞大的数据记录
记录影响显示的所有数据 这种方案要记录所有影响显示和逻辑的所有数据,无疑,这种数据量肯定是比第一种大的,内存占用会比较大,但是业务逻辑简单
这里由于我的数据量不大所以选择了第二种方式来进行处理
首先肯定要有一个Manager来负责管理数据并实现撤销和重做的分发(我命名为UndoManager),还要有一个数据对象来记录每一步的数据,由于需要记录的信息未知,可能是一个json也可能是一个对象,所以这里用最抽象的接口来表示每一步的数据信息,后续怎么处理这份数据完全根据项目需求自己定制(我命名为IRecordData)
Redo Undo的功能都是先进后出的数据结构,这种数据结构对应到程序世界的话刚好对应的是Stack,这里就先用Stack来进行思考
定义有两个Stack 分别是UndoStack 和 RedoStack 分别来存储待撤销记录和待重做记录,假设这两个Stack的当前状态如下:
假设这个时候来个一个新的步骤Step4 ,这个时候Step4需要记录,记录的过程如下:
假设我现在需要撤销一步回到Step3,具体过程如下:
假设现在我又想重做上一步,想回到Step4,具体过程如下:
至此我们的记录、撤销、重做的核心逻辑就已经基本梳理清楚了,但是发现Record还有一个小问题,问题如下:
当我们RedoStack中存在数据时,如果记录新的步骤Step4,成功之后我们会发现,现在Undo会回到Step1,Redo会回到Step2,这样流程就乱了,所以,修改一个Record的逻辑,修改后如下:
有两种处理方案,方案一为每次记录新数步骤时清空RedoStack,方案二为每次记录新数据时将RedoStack中的数据尽数移动到UndoStack中,可根据需求选择。
由于我们选择的数据记录是记录影响显示和逻辑的所有数据 本身内存占用就比记录操作要大,如果再对这两个Stack的容量不做限制,就可能会浪费很多的内存,导致程序内存占用过高。所以我们需要对UndoStack和RedoStack做容量限制,超过容量时最早进入Stack的数据直接丢弃,但Stack本身是先进后出的数据结构,显然不能支持这种操作,所以权衡利弊之后,我选择将Stack改为LinkedList,具体的操作流程是一样的。
实现
下面直接展示源码:
using System.Collections.Generic;namespace S
{public interface IRecordData{}public class UndoManager{private LinkedList<IRecordData> undoLinkedList;private LinkedList<IRecordData> redoLinkedList;private IRecordData currentData;/// <summary>/// Undo数量/// </summary>public int undoCount => undoLinkedList == null ? 0 : undoLinkedList.Count;/// <summary>/// Redo数量/// </summary>public int redoCount => redoLinkedList == null ? 0 : redoLinkedList.Count;/// <summary>/// 记录的最大容量 <=0时 代表无限容量/// </summary>public int maxCount=0;public UndoManager(){undoLinkedList = new LinkedList<IRecordData>();redoLinkedList = new LinkedList<IRecordData>();currentData = null;}/// <summary>/// 重做一步/// </summary>/// <returns></returns>public IRecordData Redo(){if (currentData != null){undoLinkedList.AddLast(currentData);}if (redoLinkedList.Count == 0){currentData = null;}else{currentData = redoLinkedList.Last.Value;redoLinkedList.RemoveLast();}return currentData;}/// <summary>/// 撤销一步/// </summary>/// <returns></returns>public IRecordData Undo(){if (currentData != null){redoLinkedList.AddLast(currentData);}if (undoLinkedList.Count == 0){currentData = null;}else{currentData = undoLinkedList.Last.Value;undoLinkedList.RemoveLast();}return currentData;}/// <summary>/// 记录/// </summary>/// <param name="recordData">记录对象</param>/// <param name="overrideRedo">是否覆盖Redo链表</param>public void Record(IRecordData recordData,bool overrideRedo=true){if (currentData != null){undoLinkedList.AddLast(currentData);}if (overrideRedo){redoLinkedList.Clear();}else{while (redoLinkedList.Last != null){IRecordData value = redoLinkedList.Last.Value;redoLinkedList.RemoveLast();undoLinkedList.AddLast(value);}}currentData = recordData;if (maxCount>0&&undoCount > maxCount) //容量维护{undoLinkedList.RemoveFirst();}}/// <summary>/// 清空undo&redo/// </summary>public void Clear(){undoLinkedList.Clear();redoLinkedList.Clear();}}
}
相关文章:

Unity UndoRedo(撤销重做)功能
需求 撤销与重做功能 思考 关于记录的数据的两点思考: 记录操作记录影响显示和逻辑的所有数据 很显然这里就要考虑取舍了: 记录操作 这种方案只需要记录每一步的操作,具体这个操作要怎么渲染和实现出来完全需要自己去实现,这…...

28条有关人工智能的名言
当谈到人工智能(AI)的潜力和潜在风险,以及无人类干预的机器学习和推理过程时,目前尚存在许多不同的观点。 只有时间会告诉我们,这些语录中哪一条是最接近未来的真实情况的。在我们尚未到达目的地之前,想一想…...
搞机器视觉项目看不起搞机器视觉培训的,实际上怎么样
搞机器视觉项目第一要务就是验收回款,往往欠款的非常严重,多数还要打通人际关系需要大量的成本。大多数机器视觉检测项目具有一定的风险,客户要求不明确,技术评估不充分,往往伴随着失败的可能性。所以做项目又累又担风…...

使用Jenkins部署项目
部署中的痛点 为什么要用Jenkins?我说下我以前开发的痛点,在一些中小型企业,每次开发一个项目完成后,需要打包部署,可能没有专门的运维人员,只能开发人员去把项目打成一个exe包,可能这个项目已…...
【机器学习与神经网络荣获诺贝尔奖】科学边界的扩展及技术革新
【机器学习与神经网络荣获诺贝尔奖】科学边界的扩展及技术革新 1)科学交叉融合的体现2)方法论的创新3)社会影响的考量 一、机器学习与神经网络的发展前景1)生产制造领域2)金融领域3)医疗领域 二、机器学习和…...
Javascript扩展符号(...)使用说明
在 ES6 中,扩展运算符(spread operator)... 可以用于在函数调用、数组字面量或对象字面量中展开数组或对象。以下是扩展运算符的一些常见用法: 1. 在函数调用中使用扩展运算符 扩展运算符可以在函数调用时展开数组或对象&#x…...

giugughk
c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话: 知不足而奋进,望远山而前行&am…...

【微服务】网关 - Gateway(下)(day8)
网关过滤工厂 在上一篇文章中,主要是对网关进行了一个总体的介绍,然后对网关中的断言进行了一个描述。在这篇文章中,主要是对网关中的最后一大核心——过滤进行介绍。 当客户端发送过来的请求经过断言之后,如果还想在请求前后添…...

【C#】创建一个控制台应用程序来管理学生成绩
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 在C#中创建一个控制台应用程序来管理学生成绩编写程序程序解释 在C#中创建一个控制台应用程序来管理学生成绩 在这篇文章中,我将向你展示如何使用C#创建…...

鸿蒙开发之ArkUI 界面篇 三十四 容器组件Tabs 自定义TabBar
如果需要修改Tabs的图标和文字之间的距离我们该怎么办呢?好在tabBar是联合类型,提供了自定义tabBar,这里就可以显示特殊图标或者是文字图片,如下图: 这里定义了myBuilder的函数,用了 来修饰,没有…...

AI核身-金融场景凭证篡改检测YOLO原理
引言 YOLO (You Only Look Once) 模型是一种先进的实时目标检测算法,它在计算机视觉领域具有重要的地位。YOLO以其速度和准确性而闻名,能够快速识别图像和视频中的各种物体。这使得它在自动驾驶、安全监控、机器人技术、医学影像分析等众多领域都有着广…...
鹅厂JS面试题——0.1+0.2=0.3吗?
首先公布答案:在JavaScript 中,0.1 0.2 ≠ 0.3 为什么? JavaScript 中的数字使用 IEEE 754 标准的双精度浮点数(64 位)进行表示。这种表示方式在处理十进制小数时,不能精确地表示某些数字。比如0.1 和 0.2 这样的十进…...

软件功能测试重点和流程有哪些?专业软件测评服务公司推荐
软件功能测试就是对产品的各功能进行验证,根据功能测试用例,逐项测试,检查产品是否达到用户要求的功能。功能测试也叫黑盒测试或数据驱动测试,只需考虑需要测试的各个功能,不需要考虑整个软件的内部结构及代码.一般从软…...

【数据结构】AVL树(C++实现)
文章目录 前言AVL树节点的定义AVL树的插入AVL树的旋转AVL树的验证AVL树的删除AVL树的性能与源码 前言 二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此&…...

AMD新推EPYC与MI325X,挑战英伟达AI市场地位
在人工智能(AI)加速器领域,AMD近日于美国旧金山举办的“推进人工智能”(Advancing AI Event)活动中,宣布了一系列新产品的发布,直接对标英伟达,意图在AI芯片市场占据更大份额。 AMD新…...

电脑桌面文件不见了怎么恢复?8个方法帮你解决问题
电脑桌面文件突然不见了凭空消失了怎么恢复?电脑桌面文件日常使用电脑时,很多用户喜欢将重要文件、快捷方式存放在桌面上,以方便快速访问。然而,有时我们会突然发现桌面上的文件不见了。桌面文件消失可能有多种原因,例…...

如果想转行AI领域却不知如何开始?可以试试这五步,超详细_ai行业怎么入行
我看了计算机科学家大卫格维茨写的一篇博客,里面介绍了如果想从事AI行业,却不知道如何开始的话,可以走下面五步,从而达到转行的目的。因为这是个国外作家写的,跟我们国内的情况有一些出入,但是大思路是没有…...

个人博客搭建 | Hexo框架
文章目录 1.Hexo安装2.创建博客3.将博客通过GitHub来部署4.更换主题 1.Hexo安装 Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他标记语言)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。搭建Hexo首先要…...
[Gtk] layout.ui
播放器layout: # <?xml version"1.0" encoding"UTF-8"?> <!-- Generated with glade 3.38.2 --> <interface> <requires lib"gtk" version"3.20"/> <object class"GtkWindow"…...

Spring MVC:精通JSON数据返回的几种高效方式
前言 在实际开发中,我们在前后端传送数据通常使用Json格式,而在Spring MVC中返回Json格式的方式有多种,接下来我将介绍其中一些。 准备工作 为了演示Json格式的数据,我们准备一个实体类,例如User,这些可以测…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...