更新(論理ティック)レートと描画(レンダリングティック)レートを分離する必要があります。
更新により、描画されるワールド内のすべてのオブジェクトの位置が生成されます。
ここでは、2つの異なる可能性、要求されたもの、外挿、および別の方法である内挿について説明します。
1。
外挿では、次のフレームでオブジェクトの(予測)位置を計算し、現在のオブジェクトの位置と次のフレームでのオブジェクトの位置の間を補間します。
これを行うには、描画される各オブジェクトにとが関連付けられている必要がvelocity
ありposition
ます。オブジェクトが次のフレームにある位置を見つけるにはvelocity * draw_timestep
、オブジェクトの現在位置に単純に追加して、次のフレームの予測位置を見つけます。draw_timestep
は、前のレンダリングティック(前の描画呼び出し)から経過した時間です。
このままにしておくと、予測された位置が次のフレームの実際の位置と一致しなかったときにオブジェクトが「ちらつき」ます。ちらつきを削除するには、予測位置、および保存することができますlerp lerp因子として前回の更新ティックからの経過時間を使用して、以前に予測位置と各ドロー・ステップで新しい予測位置の間を。これにより、高速で移動するオブジェクトが突然場所を変更した場合の動作が低下し、その特別なケースを処理することができます。この段落で述べたすべてが、外挿を使用したくない理由です。
2。
内挿とは、最後の2つの更新の状態を保存し、最後の前の更新から経過した現在の時間に基づいてそれらの間を補間する場所です。この設定では、各オブジェクトにとが関連付けられている必要がposition
ありprevious_position
ます。この場合、私たちの図面は、最悪の場合でも現在のゲーム状態の背後にある1つの更新ティックを表し、最高で現在の更新ティックとまったく同じ状態になります。
私の意見では、実装した方が簡単であるため、説明したとおりに補間が必要になるでしょう。また、現在の更新された状態のほんのわずかな秒(たとえば1/60秒)を描画しても問題ありません。
編集:
上記では実装を実行するのに十分ではない場合、ここで説明した補間方法を行う方法の例を示します。外挿については取り上げません。なぜなら、あなたがそれを好むべき現実世界のシナリオは考えられないからです。
描画可能なオブジェクトを作成すると、描画に必要なプロパティ(つまり、描画に必要な状態情報)が保存されます。
この例では、位置と回転を保存します。また、色やテクスチャ座標位置などの他のプロパティを保存することもできます(つまり、テクスチャがスクロールする場合)。
レンダリングスレッドの描画中にデータが変更されないようにするには(つまり、レンダリングスレッドの描画中に1つのオブジェクトの位置が変更されますが、他のすべてはまだ更新されていません)、何らかのタイプのダブルバッファリングを実装する必要があります。
オブジェクトにはの2つのコピーが保存されますprevious_state
。私は、配列に入れとしてそれらを参照しますprevious_state[0]
とprevious_state[1]
。同様に2つのコピーが必要current_state
です。
ダブルバッファーのどのコピーが使用されているかを追跡するためにstate_index
、更新スレッドと描画スレッドの両方で使用可能な変数を格納します。
更新スレッドはまず、独自のデータ(必要なデータ構造)を使用してオブジェクトのすべてのプロパティを計算します。そして、そのコピーcurrent_state[state_index]
にprevious_state[state_index]
、描画のための新たなデータの関連、およびコピーposition
およびrotation
へcurrent_state[state_index]
。それからstate_index = 1 - state_index
、ダブルバッファの現在使用されているコピーを反転します。
上記のパラグラフのすべてはロックを解除して行わなければなりませんcurrent_state
。更新スレッドと描画スレッドの両方がこのロックを解除します。ロックは、状態情報のコピー中にのみ解除されます。これは高速です。
次に、レンダリングスレッドで、位置と回転の線形補間を次のように行います。
current_position = Lerp(previous_state[state_index].position, current_state[state_index].position, elapsed/update_tick_length)
どこelapsed
が最後の更新ティック以降、レンダースレッドで経過したupdate_tick_length
時間であり、固定更新レートがティックごとにかかる時間です(たとえば、20FPS更新でupdate_tick_length = 0.05
)。
Lerp
上記の機能がわからない場合は、ウィキペディアの主題に関する記事「線形補間」を参照してください。ただし、lerpingが何であるかわからない場合は、おそらく、補間された描画を使用した分離された更新/描画を実装する準備ができていません。