アヒルのある日

株式会社AHIRUの社員ブログです。毎週更新!社員が自由に思いついたことを書きます。

Undo/Redoの実装(2)

こんにちは みにくい社長です。

前回に続き、Undo/Redoの実装についてです。 前回は操作時に全てのデータを保存する方法を紹介しました。
それでは操作がどうしても重くなってしまう場合があるので、今回は操作内容だけを保存する方法を紹介します。

(1)操作履歴保存用クラスを作成する

こちらは、前回のHistoryクラスをそのまま使うことができます。

(2)操作時に逆コマンドを履歴に保存する

履歴に保存するときは、操作と逆の操作を保存します。
座標を変更するなど、単純に値を書き換えるだけであれば逆コマンドは同じ内容になりますが、逆コマンドでは履歴に保存してはいけません。

public void SetPosition(Vector3 position)
{
    saveData.Position = position;
    // 履歴を追加
    _history.addHistory($"SetPosition,{position.x},{position.y},{position.z}");
}

public void SetPositionRestore(Vector3 position)
{
    saveData.Position = position;
}

(3)操作履歴から復元する

復元する際は、履歴からコマンドと引数を抽出します。 前回と同様、画面のリフレッシュは必要に応じて行ってください。

public void undo()
{
    string text = _history.getPrevious();
    restore(text);
}

public void redo()
{
    string text = _history.getNext();
    restore(text);
}

public void restore(string text)
{
    var splitTexts = text.split(',');
    switch(splitTexts[0])
    {
        case "SetPosition":
            SetPositionRestore(new Vector3(float.Parse(splitTexts[1]), float.Parse(splitTexts[2]), float.Parse(splitTexts[3])));
            // 必要に応じて画面のリフレッシュを行う
            break;
    }
}

以上です。
このようなシンプルな操作であれば逆コマンドが簡単に作れますが、複雑な操作の場合はバグを生む可能性が高いです。
一度バグが発生するとその後のデータは保障されませんので、(B)案で実装する場合はしっかりとバグチェックをしましょう。

またねー