游戏开发中如何设计一个撤销重做系统DoUnDo
作者:互联网
我现在负责做捏脸的模块,其中需要做撤销重做,老实说上一次做还是大学的时候做绘图程序有用到过,那个时候就是简单用了一个栈来操作。当时的一个核心思想是不管你绘制的是矩形、三角形、还是什么形状,底层他们都有一个基类叫图元。基于这种联想我开发出了一个实际游戏工程中用到的撤回重做系统。 我们不记录复杂的操作,复杂的操作留给系统内部cpu去计算,我们只是记录简单的数据越少越好,当然需要保证逻辑正确。这种系统还可以联想到某些游戏中的时间回流的做法。
所有的需要被DoUnDo的操作 比如一个点击 我们可以new一个对象,其中参数包括了DoUnDo的管理器,我们需要记录之前点击的按钮索引 和 当前点击的按钮索引 并且需要传一个回调函数 c#中叫委托 下图即是OnClickBigTypeImp
管理器注册命令 ADoUnDo这是抽象基类 构造函数中我们注册命令
需要注意的点就是某些控件比较复杂 比如untiy中的slider 那个滑块的值发生了变化就会执行回调函数OnValueChange 但是我们不嫩重复去注册DoUnDO的命令 那样就会有问题 需要增加类似flag变量的操作去挡这个逻辑 类似这样
整个代码在下方 类名DoUnDo.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace FaceTool
{
public abstract class ADoUnDo
{
public ADoUnDo(UnDoRecoverManager manager)
{
manager.AddToOpCommand(this);
}
public abstract void unDo(); // 撤销
public abstract void recover(); // 恢复
}
public class UnDoRecoverManager // 可以有多份实例
{
public List<ADoUnDo> opStack = new List<ADoUnDo>();
public List<ADoUnDo> recoverStack = new List<ADoUnDo>();
public void AddToOpCommand(ADoUnDo cmd) // 点击按钮 滑动滑块都需要create这个
{
if (opStack.Count >= 3000)
{
opStack.RemoveAt(0);
}
opStack.Add(cmd);
}
public void AddToRecoverCommand(ADoUnDo cmd)
{
if (recoverStack.Count >= 3000)
{
recoverStack.RemoveAt(0);
}
recoverStack.Add(cmd);
}
public void CleanAll()
{
opStack.Clear();
recoverStack.Clear();
}
public void recover()
{
if (recoverStack.Count == 0) return;
var cmd = recoverStack[recoverStack.Count - 1];
cmd.recover();
recoverStack.RemoveAt(recoverStack.Count - 1);
AddToOpCommand(cmd);
}
public void unDo()
{
if (opStack.Count == 0) return;
var cmd = opStack[opStack.Count - 1];
cmd.unDo();
opStack.RemoveAt(opStack.Count - 1);
AddToRecoverCommand(cmd);
}
}
public class ClickSubTypeCommand : ADoUnDo
{
public int currentClickIndex;
public int lastClickIndex;
public Action<int> action;
public ClickSubTypeCommand(int last, int current, Action<int> ac, UnDoRecoverManager manager) : base(manager)
{
currentClickIndex = current;
lastClickIndex = last;
action = ac;
}
public override void recover()
{
if (action != null)
{
action(currentClickIndex);
}
}
public override void unDo()
{
if (action != null)
{
Debug.Log("小类型undo" + lastClickIndex);
action(lastClickIndex);
}
}
}
public class ClickBigTypeCommand : ADoUnDo
{
public int currentClickIndex;
public int lastClickIndex;
public Action<int> action;
public ClickBigTypeCommand(int last, int current, Action<int> ac, UnDoRecoverManager manager) : base(manager)
{
currentClickIndex = current;
lastClickIndex = last;
action = ac;
}
public override void recover()
{
if (action != null)
{
action(currentClickIndex);
}
}
public override void unDo()
{
if (action != null)
{
action(lastClickIndex);
}
}
}
public class ClickDressOrAvataCommand : ADoUnDo
{
public int currentClickIndex;
public int lastClickIndex;
public Action<int> action;
public ClickDressOrAvataCommand(int last, int current, Action<int> ac, UnDoRecoverManager manager) : base(manager)
{
currentClickIndex = current;
lastClickIndex = last;
action = ac;
}
public override void recover()
{
if (action != null)
{
action(currentClickIndex);
}
}
public override void unDo()
{
if (action != null)
{
action(lastClickIndex);
}
}
}
public class ClickDressItemCommand : ADoUnDo
{
public int currentClickIndex;
public int lastClickIndex;
public Action<int> action;
public ClickDressItemCommand(int last, int current, Action<int> ac, UnDoRecoverManager manager) : base(manager)
{
currentClickIndex = current;
lastClickIndex = last;
action = ac;
}
public override void recover()
{
if (action != null)
{
action(currentClickIndex);
}
}
public override void unDo()
{
if (action != null)
{
action(lastClickIndex);
}
}
}
public class SliderValueChangeCommand : ADoUnDo
{
public int sliderIndex;
public float oldSliderValue;
public float currentSliderValue;
public Action<int, float, bool> action;
public SliderValueChangeCommand(int index, float old, float cur, Action<int, float, bool> ac, UnDoRecoverManager manager) : base(manager)
{
sliderIndex = index;
oldSliderValue = old;
currentSliderValue = cur;
action = ac;
}
public override void recover()
{
if (action != null)
{
action(this.sliderIndex, currentSliderValue, true);
}
}
public override void unDo()
{
if (action != null)
{
action(this.sliderIndex, oldSliderValue, true);
}
}
}
public class ColorValueChangeCommand : ADoUnDo
{
public int sliderIndex;
public Color last;
public Color now;
public Action<int, Color, bool> action;
public ColorValueChangeCommand(int index, Color last, Color now, Action<int, Color, bool> ac, UnDoRecoverManager manager) : base(manager)
{
sliderIndex = index;
this.last = last;
this.now = now;
action = ac;
}
public override void recover()
{
if (action != null)
{
action(this.sliderIndex,now, true);
}
}
public override void unDo()
{
if (action != null)
{
action(this.sliderIndex, last,true);
}
}
}
public class ToggleValueChangeCommand : ADoUnDo
{
public int sliderIndex;
public bool oldToggleValue;
public bool currentToggleValue;
public Action<int, bool, bool> action;
public ToggleValueChangeCommand(int index, bool old, bool cur, Action<int, bool, bool> ac, UnDoRecoverManager manager) : base(manager)
{
sliderIndex = index;
oldToggleValue = old;
currentToggleValue = cur;
action = ac;
}
public override void recover()
{
if (action != null)
{
action(this.sliderIndex, currentToggleValue, true);
}
}
public override void unDo()
{
if (action != null)
{
action(this.sliderIndex, oldToggleValue, true);
}
}
}
public class ResourceValueChangeCommand : ADoUnDo
{
public int sliderIndex;
public int oldResourceValue;
public int currentResourceValue;
public Action<int, int, bool> action;
public ResourceValueChangeCommand(int index, int old, int cur, Action<int, int, bool> ac, UnDoRecoverManager manager) : base(manager)
{
sliderIndex = index;
oldResourceValue = old;
currentResourceValue = cur;
action = ac;
}
public override void recover()
{
if (action != null)
{
action(this.sliderIndex, currentResourceValue, true);
}
}
public override void unDo()
{
if (action != null)
{
action(this.sliderIndex, oldResourceValue, true);
}
}
}
}
标签:int,void,撤销,override,manager,DoUnDo,action,public,重做 来源: https://blog.csdn.net/yangjie6898862/article/details/123640762