c#在推送之前检查堆栈中的最后一项是否等于X?
c# Check if Last item in stack equals X before pushing?
所以我希望我的问题是有道理的,但我正在 Unity 中开发一个基本的 undo/redo 系统,我试图防止添加“空”迭代(基本上如果一个对象没有t 改变位置)。
我正在为 Undo/Redo 系统使用典型的堆栈工作流,这是我将方法添加到撤消堆栈的方法:
public static void AddAction(UndoableChange action)
{
redoStack.Clear();
undoStack.Push(action);
}
我正在添加可撤消的更改,当一个对象在框架上被“选中”时,鼠标处于按下状态,然后在鼠标处于上升状态时再次被“选中”。但在我这样做之前,我想确保它不会记录我只是随机点击屏幕(这导致我不得不在实际撤消被调用之前多次撤消)。
如果堆栈中的 last/most 最近项不等于我尝试推送的 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
默认失败,因为它们是值类型,因此永远不会是同一个实例。
您想查看 before
和 after
值是否不同。
您当然可以实施任何检查相等性的方法,但最佳做法是实施 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)
所以我希望我的问题是有道理的,但我正在 Unity 中开发一个基本的 undo/redo 系统,我试图防止添加“空”迭代(基本上如果一个对象没有t 改变位置)。
我正在为 Undo/Redo 系统使用典型的堆栈工作流,这是我将方法添加到撤消堆栈的方法:
public static void AddAction(UndoableChange action)
{
redoStack.Clear();
undoStack.Push(action);
}
我正在添加可撤消的更改,当一个对象在框架上被“选中”时,鼠标处于按下状态,然后在鼠标处于上升状态时再次被“选中”。但在我这样做之前,我想确保它不会记录我只是随机点击屏幕(这导致我不得不在实际撤消被调用之前多次撤消)。
如果堆栈中的 last/most 最近项不等于我尝试推送的 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
默认失败,因为它们是值类型,因此永远不会是同一个实例。
您想查看 before
和 after
值是否不同。
您当然可以实施任何检查相等性的方法,但最佳做法是实施 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)