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

元に戻すの標準的な期待される動作は、アクションを元に戻すことができ、次に元に戻すを使用する前に戻るためにやり直すことができます...新しいアクションを実行しない限り! 新しいアクションは、すべてのやり直し機能を削除します。

概念化に役立つように (括弧は現在の状態を示します):

Act1 -> Act2 -> (Act3)

2回元に戻すと...

(Act1) -> Act2 -> Act3

新しいアクションが実行されない場合は、この時点でやり直すことができます。ユーザーが NewAction を実行すると、次のようになります。

Act1 -> (NewAct2)

...以上です!Act3 は今では忘れ去られ、昨日のゴミのように捨てられています。この代替手段は、実装が難しすぎて、使用するのが非常に直感的ではありません!. たとえば、タイルを作成して色を変更し、タイル作成前に元に戻して別の場所にタイルを作成するとします。やり直すと、その新しいタイルの色は変わりますか? 古いタイルは新しい色で再現されますか? もう一度元に戻すと、最後の編集セットではなく最初の編集セットが返されますか? うん!

これは、Photoshop のような複雑なプログラムでさえ機能する方法であるため、マップ エディターが他の方法で動作することを期待するのは合理的ではありません。多くのプログラムは Redo をサポートしていません。これは、物事を自分よりも難しくする時期の1つにすぎません。

基本的にはそのままでいいみたいですね!

于 2013-03-16T10:48:41.677 に答える
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をマップに挿入します。

于 2013-03-18T09:37:02.913 に答える