Сначала вам нужно что-то, что вы можете сохранить соответствующие данные, например,
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 struct UndoableChange
{
private List<ObjectState> _before;
private List<ObjectState> _after;
public UndoableChange (List<ObjectState> before, List<ObjectState> after)
{
_before = before;
_after = after;
}
public void Undo()
{
foreach(var state in _before)
{
state.Apply();
}
}
public void Redo()
{
foreach(var state in _after)
{
state.Apply();
}
}
}
Тогда для контроллера я бы использовал два Stack
. A Stack
является «первым пришел - первым вышел», именно то, что вам нужно. Вы добавляете новые записи, используя Push
, и используя Pop
, вы извлекаете последний добавленный элемент и в то же время удаляете его из стека. Так что это выглядело бы как
public static class UndoRedo
{
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);
}
public static void Redo()
{
if(redoStack.Count == 0) return;
var lastAction = redoStack.Pop();
lastAction.Redo();
undoStack.Push(lastAction);
}
public static void AddAction(UndoableChange action)
{
redoStack.Clear();
undoStack.Push(action);
}
}
Я не знаю, как именно ваш пользователь взаимодействует с объектами, но теперь вы всегда будете делать что-то вроде
// at some point store the initial values
var before = new ObjectState (selectedGameObject);
//TODO Apply all your changes to the selected object
// get the new values
var after = new ObjectState (selectedGameObject);
// Log to the history
UndoRedo.AddAction(new UndoableChange(before, after));
или использовать списки для всех выбранных объектов соответственно например, просто используя Linq
using System.Linq;
...
var before = selectedGameObjects.Select(obj => new ObjectState(obj)).ToList();
//TODO Apply all your changes to all the selected objects
var after = selectedGameObjects.Select(obj => new ObjectState(obj)).ToList();
UndoRedo.AddAction(new UndoableChange(before, after));
Примечание: напечатано на смартфоне, но я надеюсь, что идея проясняется