4

サーバー クライアントの Winsock ゲームで推測航法を実装する方法を理解するのに少し苦労しています。

私はインターネットで、正確に説明する適切な説明を探していました。

  1. サーバーからクライアントにメッセージを送信する必要がある場合

  2. 更新メッセージを受信しない場合、クライアントはどのように動作する必要がありますか? 新しい予測位置を計算するために、予測位置を現在の位置として使用し続けますか?

私が使用している推測航法は次のとおりです。

path vector = oldPosition - oldestPosition
delta time = oldTime - oldestTime
delta velocity = path vector / delta time
new delta time = current time / oldest time
new prediction = oldPosition + new delta time * delta velocity

これが使用する正しい式であることを願っています! :)

また、接続タイプが UDP であり、ゲームがサーバー上でのみプレイされることにも注意してください。サーバーは更新メッセージをクライアントに送信します。

誰でも私の質問に答えて助けてもらえますか?

ありがとう

4

2 に答える 2

10

推測航法では、運動学的状態と呼ばれる変数のグループが機能する必要があります。通常、特定のオブジェクトの位置、速度、加速度、向き、および角速度が含まれます。位置のみを探している場合は、方向と角速度を無視することを選択できます。位置だけでなく方向も予測したい場合は、コメントを投稿してください。回答を更新します。

ネットワーク ゲームの標準的な推測航法アルゴリズムを次に示します。

推測航法式

上記の変数は次のように記述されます。

P t : 推定位置。出力

P O : オブジェクトの最新の位置更新

V O : オブジェクトの最新の速度更新

A O : オブジェクトの最新の加速度更新

T: 現在時刻と最後の更新のタイムスタンプとの間の経過秒数。パケットが受信された時刻ではありません。

これを使用して、サーバーから更新を受信するまでオブジェクトを移動できます。次に、推定された位置 (上記のアルゴリズムの最新の出力) と、受信したばかりの実際の位置の 2 つの運動学的状態があります。これら 2 つの状態を現実的にブレンドするのは難しい場合があります。


1 つのアプローチは、古い方向を将来に投影しながら、2 つの状態の間に線を作成することです。ベジエ スプライン、 Catmull-Rom スプラインエルミート曲線(他の方法のリストはこちら) などの曲線を作成することをお勧めします。したがって、新しい状態を取得するまで、古い状態を使用し続けてください。つまり、あなたが溶け込んでいる状態が古い状態になるときです。

もう 1 つの手法は、射影速度ブレンドを使用することです。これは、2 つの射影 (最後の既知の状態と現在の状態) のブレンドであり、現在レンダリングされた位置は、特定の時間における最後の既知の速度と現在の速度のブレンドです。

「Game Engine Gems 2」という本を引用しているこの Web ページは、推測航法の宝庫です。

ネットワーク化されたゲームのための信頼できる推測航法

編集:上記のすべては、更新を取得しない場合にクライアントがどのように動作するかを示しています。「サーバーからクライアントにメッセージを送信するタイミング」に関して、Valve は、優れたサーバーは約 15 ミリ秒間隔 (1 秒あたり約 66.6 ミリ秒) で更新を送信する必要があると述べています。

注: 「Valveが言う」リンクには、ソース マルチプレイヤー ネットワークを媒体として使用した、ネットワークに関する優れたヒントも記載されています。時間があればチェックしてみてください。

編集 2 (コードの更新!):

C++/DirectX 環境でこのようなアルゴリズムを実装する方法を次に示します。

struct kinematicState
{
     D3DXVECTOR3 position;
     D3DXVECTOR3 velocity;
     D3DXVECTOR3 acceleration;
};

void PredictPosition(kinematicState *old, kinematicState *prediction, float elapsedSeconds)
{
     prediction->position = old->position + (old->velocity * elapsedSeconds) + (0.5 * old->acceleration * (elapsedSeconds * elapsedSeconds));`
}

kinematicState *BlendKinematicStateLinear(kinematicState *olStated, kinematicState *newState, float percentageToNew)
{
     //Explanation of percentateToNew:
     //A value of 0.0 will return the exact same state as "oldState",
     //A value of 1.0 will return the exact same state as "newState",
     //A value of 0.5 will return a state with data exactly in the middle of that of "old" and "new".
     //Its value should never be outside of [0, 1].

     kinematicState *final = new kinematicState();

     //Many other interpolation algorithms would create a smoother blend,
     //But this is just a linear interpolation to keep it simple.

     //Implementation of a different algorithm should be straightforward.
     //I suggest starting with Catmull-Rom splines.

     float percentageToOld = 1.0 - percentageToNew;

     final->position = (percentageToOld * oldState->position) + (percentageToNew * new-State>position);
     final->velocity = (percentageToOld * oldState->velocity) + (percentageToNew * newState->velocity);
     final->acceleration = (percentageToOld * oldState->acceleration) + (percentageToNew * newState->acceleration);

     return final;
}

幸運を祈ります。ゲームで何百万ドルも稼いだら、私をクレジットに入れてみてください ;)

于 2014-01-03T22:37:11.933 に答える
1

これは、一般的で広範な質問です。

クライアント側で推測航法を使用するゲームサーバーを実装している場合 (そうしていると思います)、サーバーから新しい入力を取得しない限り、値を推定し続ける必要があります。その時点で、新しい位置/時間/保存したものを強制的に更新する必要があります。サーバーの応答がない場合は、最新の見積もりに基づいて自分で見積もりを行う必要があります。

ちなみに以下のような気がします

new delta time = current time / oldest time

むしろ次のようなものであるべきです

new delta time = current time - oldTime

最後の予測までの経過時間を取得するため。そうしないと、(単位として使用される最も古い時間と比較して) 時間が経過するとシステムが速くなり、時間が経過すると遅くなると想定します。直線運動方程式 (加速されていない) は new_s = s_0 + vel * t です。

于 2014-01-03T22:28:39.367 に答える