如何解决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 默认情况下失败,因为它们是值类型因此永远不会是同一个实例。
您更希望查看 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)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。