c# 在推送之前检查堆栈中的最后一项是否等于 X?

如何解决c# 在推送之前检查堆栈中的最后一项是否等于 X?

所以我希望我的问题有意义,但我正在 Unity 中开发一个基本的撤消/重做系统,并且我试图防止添加“空”迭代(基本上如果对象没有改变位置) .

我正在使用用于撤消/重做系统的典型堆栈工作流,这是我向撤消堆栈添加方法方法

public static void AddAction(UndoableChange action)
{
    redoStack.Clear();
    undoStack.Push(action);
}

当鼠标按下时在框架上“选择”一个对象时,我正在添加可撤销的更改,然后在鼠标抬起时再次添加。但在我这样做之前,我想确保它不会记录我只是随机点击屏幕(这导致我必须在调用实际撤消之前多次撤消)。
检查堆栈中最后/最近的项目是否不等于我尝试推送的 UndoableChange 的语法是什么?

我已经试过了,但它仍然记录“空”点击:

public static void AddAction(UndoableChange action)
{
    if (undoStack.Count >0 && undoStack.Peek().Equals(action))
        return;

    redoStack.Clear();
    undoStack.Push(action);
}

这个好像应该比较简单。任何帮助将不胜感激!


完整脚本如下

    public struct ObjectState
{
    // The transform this data belongs to
    private Transform transform;

    private Vector3 localPosition;
    private Quaternion localRotation;
    private Vector3 localScale;

    private bool active;

    public ObjectState(GameObject obj)
    {
        transform = obj.transform;
        localPosition = transform.localPosition;
        localRotation = transform.localRotation;
        localScale = transform.localScale;

        active = obj.activeSelf;
    }

    public void Apply()
    {
        transform.localPosition = localPosition;
        transform.localRotation = localRotation;
        transform.localScale = localScale;

        transform.gameObject.SetActive(active);
    }
}
public struct UndoableChange
{
    private ObjectState _before;
    private ObjectState _after;

    public UndoableChange(ObjectState before,ObjectState after)
    {
        _before = before;
        _after = after;
    }

    public void Undo()
    {
        _before.Apply();
    }

    public void Redo()
    {
        _after.Apply();
    }
}

public static class UndoRedoControls
{
    private static Stack<UndoableChange> undoStack = new Stack<UndoableChange>();
    private static Stack<UndoableChange> redoStack = new Stack<UndoableChange>();

    public static void Undo()
    {
        if (undoStack.Count == 0) return;

        var lastAction = undoStack.Pop();

        lastAction.Undo();

        redoStack.Push(lastAction);
        Debug.Log("UNDOING");
    }

    public static void Redo()
    {
        if (redoStack.Count == 0) return;

        var lastAction = redoStack.Pop();

        lastAction.Redo();

        undoStack.Push(lastAction);
        Debug.Log("REDOING");
    }

    public static void AddAction(UndoableChange action)
    {
        if (undoStack.Count >0 && undoStack.Peek().Equals(action))
            return;

        redoStack.Clear();
        undoStack.Push(action);
    }
}

解决方法

正如默认情况下所说,Equals 检查 引用相等 的类,这不是您想要做的,并且 struct 的 afaik 默认情况下失败,因为它们是值类型因此永远不会是同一个实例。

您更希望查看 beforeafter 值是否不同。

您当然可以实现任何检查相等性的方法,但最佳实践是实现 IEquatable<T>

因此你可以使用类似的东西

public struct ObjectState : IEquatable<ObjectState>
{
    // The transform this data belongs to
    public readonly Transform transform;

    private readonly Vector3 localPosition;
    private readonly Quaternion localRotation;
    private readonly Vector3 localScale;

    private readonly bool active;

    public ObjectState(GameObject obj)
    {
        transform = obj.transform;
        localPosition = transform.localPosition;
        localRotation = transform.localRotation;
        localScale = transform.localScale;

        active = obj.activeSelf;
    }

    public void Apply()
    {
        transform.localPosition = localPosition;
        transform.localRotation = localRotation;
        transform.localScale = localScale;

        transform.gameObject.SetActive(active);
    }

    public override bool Equals(object obj)
    {
        if (!(obj is ObjectState objState)) return false;
        return Equals(objState);
    }

    public bool Equals(ObjectState other)
    { 
        if(other.transform != transform) return false;

        // For now using the approximations Unity uses by default
        // with precision of 0.00001
        return other.localPosition == localPosition && other.localRotation == localRotation && other.localScale == localScale;
    }

    public static bool operator ==(ObjectState a,ObjectState b)
    {  
        return a.Equals(b);
    }

    public static bool operator !=(ObjectState a,ObjectState b)
    {
        return !a.Equals(b); 
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int hash = transform.GetHashCode();
            hash = 31 * hash + localPosition.GetHashCode();
            hash = 31 * hash + localRotation.GetHashCode();
            return 31 * hash + localScale.GetHashCode(); 
        }
    }
}

现在您可以实际检查两个 ObjectState 实例是否相等。

现在你可以使用这个

public struct UndoableChange : IEquatable<UndoableChange>
{
    private ObjectState _before;
    private ObjectState _after;

    // Check if this is a valid action
    // It refers to the same object
    // and actually something was changed
    public bool IsValid()
    {
        return _before.transform == _after.transform && _before != _after;
    }

    public UndoableChange(ObjectState before,ObjectState after)
    {
        _before = before;
        _after = after;
    }

    public void Undo()
    {
        _before.Apply();
    }

    public void Redo()
    {
        _after.Apply();
    }

    public override bool Equals (object obj)
    {
        if(!(obj is UndoableChange other)) return false;
        return Equals (other);
    }

    public bool Equals (UndoableChange other)
    {
        return other._before == _before && other._after == _after;
    }

    public static bool operator ==(UndoableChange a,UndoableChange b)
    {
        return a.Equals(b);
    }

    public static bool operator !=(UndoableChange a,UndoableChange b)
    {
        return !a.Equals(b);
    }

    public override int GetHashCode ()
    {
        unchecked
        {
            return _before.GetHashCode() * 31 + _after.GetHashCode();
        }
    }
}

现在你可以检查两件事

if(action.IsValid())

if(undoStack.Peek() != action)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?