1

所以我想要我在游戏中使用的 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 中,它将遍历所有已更正的图块。如果更正的图块是被点击的图块并且它实际上已经改变了,它将把它添加到撤消和重做列表中。您现在应该忽略重做列表,因为重做功能尚未实现。我想让撤消功能首先工作。

因此,在函数的最后一部分,我将新操作添加到列表中,但同样,我认为我需要做其他事情,然后当您在列表中的某个位置而不是最后时添加。

希望你明白我想要什么。
谢谢!

4

2 回答 2

5

撤消的标准预期行为是您可以撤消操作,然后重做以返回到使用撤消之前...除非您执行新操作!新操作会删除所有重做功能。

为了帮助概念化(括号显示当前状态):

第 1 幕 -> 第 2 幕 -> (第 3 幕)

撤消两次给...

(Act1) -> Act2 -> Act3

现在,如果没有采取新的操作,您可以在此时重做。现在,如果用户执行 NewAction,我们会得到:

Act1 -> (NewAct2)

……就是这样!Act3 现在刚刚被遗忘,像昨天的垃圾一样被丢弃。替代方案太难实现并且使用起来非常不直观!就像您创建一个图块,更改颜色,然后在创建图块之前撤消并在其他地方创建图块一样。如果你重做,新的瓷砖会改变颜色吗?旧瓷砖会以新颜色重新出现吗?如果再次撤消,重做是否会返回第一组编辑而不是最后一组?呸!

这就是像 Photoshop 这样的复杂程序的工作方式,因此期望地图编辑器以其他方式运行是不合理的。许多程序甚至不支持重做,所以你是否想要支持它取决于你!这只是那些让事情变得比他们更难的时代之一。

基本上,您似乎可以按原样进行!

于 2013-03-16T10:48:41.677 回答
1

一般来说,你应该有一个 Stack of 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 不为空,请尝试将其从地图中删除。
- 将 newTile 插入地图。

还原:
- 如果 newTile 不为空,则将其从地图中删除
- 将 oldTile 插入地图。

于 2013-03-18T09:37:02.913 回答