2

Java デスクトップ フライト シミュレーションを開発しています。コックピットで発生するすべてのパイロット アクション (スロットル コントロール、ステアリング、武器展開など) を記録して、後でこれらのイベントを表示 (またはライブ ストリーミング) できるようにする必要があります。

イベントの再生に視覚的なリプレイ機能を追加して、時間を前後に移動するときにコックピットを視覚的に確認できるようにしたいと考えています。イベントを時系列で再生する限り、リプレイは問題ありませんが、巻き戻しは少しトリッキーです。

巻き戻し機能をどのように実装しますか?

4

6 に答える 6

3

修正されたMemento パターンを使用します。

違いは、すべてのパイロット アクションのリストを Memento オブジェクトに格納することです。

Memento パターンは通常、ロールバック (元に戻す) に使用されますが、あなたのケースではそれが適用されることもわかりました。パイロット アクションも保存可能な状態にする必要があります。

于 2009-07-07T13:30:29.440 に答える
2

コマンド パターンのバリアントを使用して、パイロット アクションのそれぞれに元に戻す操作を実装させることができます。

たとえば、あなたのパイロットがアクションを左に操縦した場合 (簡単なことですが)、その逆は右に操縦します。

public interface IPilotAction {
    void doAction(CockpitState state);
    void undoAction(CockpitState state);
}

public class ThrottleControl implement IPilotAction {

     private boolean increase;
     private int speedAmount;

     public ThrottleControl(boolean increase, int speedAmount) {
         this.increase = increase;
         this.speedAmount = speedAmount;
     }

     public void doAction(CockpitState state) {
         if (increase) {
            state.speed += speedAmount;
         } else {
            state.speed -= speedAmount;
         }
     }

     public void undoAction(CockpitState state) {
         if (increase {
             state.speed -= speedAmount;
         } else {
             state.speed += speedAmount;
         }
}
于 2009-07-07T13:29:39.160 に答える
1

あなたが探しているのは、実際にはCommandパターンとMementoパターンのブレンドです。すべてのパイロット アクションは、ログに記録できるコマンドである必要があります。ログに記録されたすべてのコマンドには、必要に応じて、(A) がコマンドに含まれておらず、(B) を確実に再構築できないという追加の状態を記録するメモがあります。「B」は重要です。この状態は、ほとんどすべての重要なドメインに存在します。正確な再構築を回復するには、保存する必要があります。

これらの概念を統合し、基本的に各コマンドに記念品を添付すると、一連の確定的なイベントが完全にログに記録されます。

これについては、別の回答で詳しく説明しました。設計パターンを特定のニーズに大幅に適合させることを恐れないでください。:)

RE のパフォーマンスに関する懸念事項:

数分のジャンプが頻繁に発生すると予想され、実装後にパフォーマンスのボトルネックが実行不可能であることが判明した場合は、ロギング メカニズムと共に時折の「スナップショット」を実装することをお勧めします。基本的に、実行する必要があるログのローリングの量を最小限に抑えるために、アプリケーション全体の状態を数分ごとに保存します。次に、最も近い保存された状態から目的の時間枠にアクセスできます。これは、アニメーションやメディアのキー フレームに似ています。

于 2009-07-07T13:32:55.160 に答える
0

直接的な答えではありませんが、取り消しの実装に関する議論をチェックしてください。ほとんどの場合、テキスト エディターに関するものになりますが、同じ原則が適用されます。

不変性を好む場合に役立ちます。複雑な変更を元に戻すのは困難です。自動化されたシステムでさえ、パフォーマンスの問題を抱えています (ソフトウェア トランザクション メモリ、STM)。

于 2009-07-07T13:39:30.333 に答える
0

シミュレーションの「状態」が関数になるようにシミュレーションを実装したことを確認してください。つまり、時間の関数です。

時間での初期状態が与えられると、任意T0の時間でシミュレーション フレームを構築できるはずです。たとえば、初期の定常状態でイベントがない (まだ) 場合は、恒等関数に等しいので.TnnTn == Tn+1

ある時点でパイロット アクション イベントが与えられると、任意Taのフレームを作成できるはずです。したがって、イベントは、引数として時間値を取り、その時間のシミュレーションのフレームを返す関数を変更するものと考えてください。Ta+nn

シミュレーションの制御状態を表す (時間、関数) ペアのZipperとしてイベントの履歴を実装します。「現在」の状態がフォーカスされ、右側に将来の状態のリストが表示され、左側に過去の状態が表示されます。そのようです:

([past], present, [future])

シミュレーションの状態が変化するたびに、新しい状態関数を に記録しfutureます。シミュレーションの実行は、リストから関数を取り出しfutureて現在の時間を渡すという問題になります。past逆方向に実行することは、代わりにリストからイベントを取り出すことを除いて、まったく同じです。

したがって、時間に達していて、Tn時間まで巻き戻したい場合は、属性が 未満の最新の状態Tn-1のリストを調べます。その属性に渡すと、 time でのシミュレーションの状態が得られます。pasttimen-1n-1functionTn-1

ここでは、Java で Zipper データ構造を実装しました。

于 2009-07-07T16:19:19.653 に答える
0

すべてのインスタンスで状態を保存できます。状態 (風速、オブジェクト速度 + 方向 / 制御入力状態、x 30fps x 20 分 ~ 36 メガバイト) に 1kb。効果)

それはあなたにとっては多すぎるかもしれませんが、実装するのが最も簡単です. 状態を再作成するために作業を行う必要はまったくなく (インスタントアクセス)、状態間を非常に簡単に補間できます (再生を高速化/低速化するため)。ディスク容量については、圧縮するだけで録音中に実行できるため、再生中にメモリが占​​有されることはありません。

スペースを節約する簡単な方法は、記録ファイルにページ番号を付け、各ビンを個別に圧縮することです。つまり、毎分 1 つの zip ストリームです。そうすれば、現在のビンを解凍するだけでメモリを節約できますが、それは状態データの圧縮率に依存します。

コマンドを記録し、クラス ファイルに複数方向の再生を実装させるには、多くのデバッグ作業が必要になります。再生を遅くしたり速くしたりすると、計算負荷も高くなります。節約できるのはスペースだけです。

それがプレミアムである場合、それを節約する他の方法もあります。

于 2009-08-23T17:12:56.973 に答える