所以我想在我的游戏中使用MapEditor的撤消功能。我得到了部分工作。当我点击地图时,它会将旧图块和新图块存储在单独的列表中。当我按下Ctrl + Z时,它将撤消上一个操作,依此类推。
我的问题是当你取消某些操作,然后向列表添加新操作时。那会发生什么?我应该只在列表末尾添加新操作,还是应该从列表中的当前位置删除所有内容,直到结束,然后将新操作添加到列表中。
我的问题是我无法解决这个问题。我尝试了很多事情,但是当这种情况发生时,它们都被打破了。
因此,我需要知道在将新操作添加到撤消列表时如何继续。
添加到撤消列表时的当前代码:
private void UpdateCorrectedTiles(Dictionary<TileSide, Tile> correctedTiles, bool saveEditedTiles)
{
List<Tile> tmpUndoTilesList = new List<Tile>();
List<Tile> tmpRedoTilesList = new List<Tile>();
foreach (Tile tile in tiles)
{
foreach (KeyValuePair<TileSide, Tile> correctedTile in correctedTiles)
{
if (tile.GetTilePosition() == correctedTile.Value.GetTilePosition())
{
if (correctedTile.Key == TileSide.Clicked && saveEditedTiles
&& Tile.IsTileChanged(previousClickedTile, correctedTile.Value))
{
Tile undoTile = Tile.CreateCloneTile(previousClickedTile);
Tile redoTile = correctedTile.Value;
tmpUndoTilesList.Add(undoTile);
tmpRedoTilesList.Add(redoTile);
}
TileInfo info = correctedTile.Value.GetTileInfo();
Vector2 frames = correctedTile.Value.GetCurrentFrame();
tile.SetTileInfo(info);
tile.SetCurrentFrame(frames);
}
}
}
if (saveEditedTiles && tmpUndoTilesList.Count > 0 && tmpRedoTilesList.Count > 0)
{
undoTilesList.Add(tmpUndoTilesList);
redoTilesList.Add(tmpRedoTilesList);
currentUndoRedoIndex = undoTilesList.Count - 1;
}
}
此代码的作用是在Foreach中,它将循环遍历已更正的所有切片。如果更正的图块是单击的图块并且实际已更改,则会将其添加到“撤消”和“重做列表”中。您现在应该忽略重做列表,因为重做功能尚未完成。我想让撤消功能先工作。
所以在函数的最后一部分,我将新动作添加到列表中,但是,我认为我需要做一些其他事情,然后在列表中的某个位置添加时,而不是在最后添加。
希望你明白我的意思。
谢谢!
答案 0 :(得分:5)
撤消的标准预期行为是您可以撤消操作,然后重做以在您使用撤消之前返回...除非您执行新操作!新操作会删除所有重做功能。
帮助概念化(parens显示当前状态):
Act1 - &gt; Act2 - &gt; (Act3)
撤消两次给...
(Act1) - &gt; Act2 - &gt; ACT3
如果没有采取新的行动,现在你可以重做。现在,如果用户执行NewAction,我们得到:
Act1 - &gt; (NewAct2)
......那就是它! Act3现在被遗忘了,像昨天的垃圾一样丢弃了。替代方案太难实现,使用起来非常不直观!就像你创建一个图块,更改一个颜色,然后在创建图块之前撤消回来,并在其他地方创建一个图块。如果你重做,新的瓷砖会改变颜色吗?旧瓷砖是否以新颜色重新出现?如果再次撤消,重做是否会返回第一组编辑而不是最后一组?呸!
即使像Photoshop这样的复杂程序也能工作,所以期望地图编辑器以任何其他方式行事都是不合理的。许多程序甚至不支持重做,所以如果你想支持它,它取决于你!这只是一个让自己比自己更难的事情之一。
基本上,你似乎很高兴按原样行事!
答案 1 :(得分:1)
一般来说,你应该有一个IMapChange堆栈,其中IMapChange看起来像这样:
public interface IMapChange
{
//Performs the change on a TileMap
Boolean PerformChange(TileMap map);
//Reverts the change on a TileMap
Boolean RevertChange(TileMap map);
}
您应该有一个被调用的方法来进行更改:
public void SetTile(Vector2 position, int tileId)
{
Tile oldTile = Map.GetTile(position);
Tile newTile = new Tile(position, tileId);
MapChange change = new MapChange(oldTile, newTile);
//Only push to cahngestacks if successfull
if (change.PerformChange(Map))
{
ChangeStack.Push(change);
//We don't want you to be able to "redo" anymore if you do something new.
RedoStack.Clear();
}
}
public void RemoveTile(Vector2 position)
{
Tile oldTile = Map.GetTile(position);
Tile newTile = null;
MapChange change = new MapChange(oldTile, newTile);
//Only push to changestacks if successfull
if (change.PerformChange(Map))
{
ChangeStack.Push(change);
//We don't want you to be able to "redo" anymore if you do something new.
RedoStack.Clear();
}
}
撤消可能如下所示:
public void Undo()
{
var lastChange = ChangeStack.Pop();
//Try to revert. If revert fails, put the change back in the stack
if (!lastChange.RevertChange(Map))
ChangeStack.Push(lastChange);
else
RedoStack.Push(lastChange);
}
并像这样撤消:
public void Redo()
{
var lastChange = RedoStack.Pop();
//Try to perform. If successfull, put back in ChangeStack
if (lastChange.PerformChange(Map))
ChangeStack.Push(lastChange);
else
RedoStack.Push(lastChange);
}
PerformChange和RevertChange基本上是:
执行:
- 如果oldTile不为null,请尝试将其从地图中删除
- 将newTile插入地图。
还原:
- 如果newTile不为null,则将其从地图中删除
- 将oldTile插入地图。