其他分享
首页 > 其他分享> > 游戏开发中如何设计一个撤销重做系统DoUnDo

游戏开发中如何设计一个撤销重做系统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