web-dev-qa-db-ja.com

JavaScriptバックエンドとフロントエンドを備えたマルチプレイヤーゲーム。ベストプラクティスは何ですか?

Node.js でWebマルチプレイヤーゲームを作成することを考えています。これは、バックエンドとフロントエンドで同じ言語を使用することを意味します。それはリアルタイムであり、各「部屋」で最大約20人になるので、私はいくつかの考えを持っています:

  1. すべてのユーザーが同じものを同時に見ることができるように、すべてのユーザー間の遅延をどのように補正しますか?各プレーヤーの平均ping時間を追跡し、最も遅いプレーヤーを見つけて、他のクライアントに、全員が可能な限り同期するように、各プレーヤーを遅延させる必要がある時間(ミリ秒単位)を通知することを考えています。

  2. 私はゲームコードをバックエンドとフロントエンドで実行することを考えており(両端がJavaScriptであるため)、バックエンドの「実際のゲーム」と同期するためのエラー訂正メカニズムを備えています。そうすれば、ゲームはフロントエンドでスムーズに実行され、同期が発生したときにわずかな不具合が発生するだけです。また、詐欺師はバックエンドゲームに同期されるため、フロントエンドのJavaScriptハッキングを最小限に抑えることができます。

  3. ソケット(キー押下)を介してプレーヤーのアクションを受信する必要がある場合は、他のすべてのクライアントに他のプレーヤーのアクションを通知し、その間にバックエンドでゲームを「プレイ」し、ゲーム状態全体のすべての人に同期情報を1回ずつ送信します。それらを同期している間?

どう思いますか?考慮または注意を払う必要があるものは他にありますか?

マルチプレイヤーゲームに関する考えやドキュメントや記事へのリンクを投稿してください。


編集:これらは便利です:

37
stagas

1-不可能です。メッセージがクライアントに到着するまでにかかる正確な時間はわかりません。また、次に送信するメッセージに測定が適用されるとは限りません。あなたができる最善のことは概算ですが、人々はわずかに異なるものを見ると常に想定する必要がありますOR同じものをわずかに異なる時間に送信します。現在の状態を送信することをお勧めします誰にでも、補間/外挿を使用してゲームプレイをスムーズにし、プレーヤー間および時間の経過とともに遅延が変化する、過去数ミリ秒のゲームを誰もが見ることができるようにします。一般に、これが大きな問題になることはめったにありません。本当に必要な場合サーバー上のいくつかの過去の状態をバッファリングするために、それらの間を補間し、異なる古いデータを異なる人々に送信して、彼らが見ているものを同期しようとすることができますが、クライアント側のシミュレーションと送信時間のジッターと組み合わせると、まだいくつかが見られますマシン間の違い。

2-一般的な方法は、サーバーでシミュレーションを実行し、定期的な(小さな)状態の更新をクライアントに送信することです。クライアントは通常、独自のシミュレーションを実行し、独自の予測/補間状態とサーバーが送信している信頼できる状態をブレンドする方法を持っています。ユーザー入力以外のすべての決定は、サーバー側で行う必要があります。最終的に、これらをブレンドする方法は、滑らかな外観と正確な状態の間のトレードオフにすぎないため、外観上の決定を行う必要があります。

3-クライアントは通常、キー押下を論理アクションに変換する必要があります。サーバーはキーを気にしません。その論理アクションをサーバーに送信すると、必要に応じて他のクライアントにブロードキャストできます。通常、ここでは何もする必要はありませんが、アクションによって引き起こされる関連する変更は、通常、ゲームの状態を変更するだけなので、その状態の通常のブロードキャストで送信されます。

27
Kylotan

他の答えがうまくいくので、私はあなたのポイントに直接対処しません。ただし、リアルタイムのパフォーマンスを大幅に向上させることが約束されているHTML5、WebSocket、Cometを調べることをお勧めします。これらのテクノロジーを使用すると、長時間実行されるHTTPリクエストを実行できるため、クライアントがサーバーをポーリングするのではなく、サーバーがデータをクライアントにプッシュできます。これにより、処理速度が大幅に向上します。

役立つと思われるリソースを次に示します。

5
Tauren
  1. これを行うのは非常に難しく、「最も遅い」への同期に多くの問題が見られます。これを緩めて、クライアントが「結果整合性」になるようにすることはできますか?

  2. いいですね。

  3. フロントエンドからバックエンドに短いアクションイベントを送信し、バックエンドにゲームの状態を変更させ、ゲームの状態の変更イベントをクライアントに公開します。必要なイベントのみを適切なサブスクライバーに送信することに細心の注意を払います。この時点で、一致していないように見えるイベントや、偽物/ハッキングのように見えるイベントを破棄できます。

1
Santi

最善の方法は、すべてのオブジェクトを1つの場所、つまりサーバーで追跡することです。誰もがサーバーからの情報を「実際に発生する」よりも1移動時間遅れて表示し、ユーザーのコマンドは1回の移動でサーバーに登録します。これを回避する方法は本当にありません。一部のアプリケーションでは、サーバーの応答を待たずにすぐに自分の動きをシミュレートすることが実用的ですが、これは間違いなくタイミングプログラミングの悪夢につながり、人々は通常、お互いが「遅れている」のを目にします。衝突検出はほとんど不可能です。

これの正味の効果は、コマンドを入力してから実際に発生するのを確認するまでの速度が遅くなることですが、うまくいけば、人々はこれに対処する方法を学び、少し早くコマンドを入力して補正しようとします。接続が遅いと、ペースの速いリアルタイムゲームは不可能です。

1
MatsT

学ぶためのサンプルコードを探しているなら、PongのオンラインマルチプレイヤーゲームがありますActionScriptで実行 、サーバー側の物理演算はクライアントによって補間されます。

そのPongの例は、 nion platform に基づいて構築されており、最大1000の同時クライアント接続で無料で利用できます。

UnionにはJavaScriptクライアントフレームワークがありますOrbiterMicro(JavaScriptクライアント)

また、サーバー側のロジックをJavaScriptで記述することもできます。JavaScriptを使用したルームモジュールの作成を参照してください。

(完全な開示:私はUnionの共同創設者です。)

1
colin moock

典型的なアプローチの1つは、すべてのクライアントをサーバーにロックされた同じフレームレートで実行しようとしないことです...それは単に醜くなります。代わりに、頻繁に更新を送信して、クライアントが新しい更新を受信するたびに更新できるようにします。

通常、クライアントは状況が短期間どのように進行するかを予測し、サーバーからの更新によって修正されます。時間補正を適用することもできます。たとえば、サーバーが「プレーヤー2は速度Vで移動しているPにいる」と言った場合、最近のpingに基づいてそのメッセージが何歳であるかを確認し、位置をPからに修正できます。 P + x*D

0
Mr. Boy

読む価値のあるレイテンシーの問題に関してこれに似た別の質問に答えました。ゲームによっては、最も遅いクライアントとの同期が最善の解決策ではない場合があります。

その他のStackOverflowの質問: マルチプレイヤーゲームの動きの同期

0
Evan Shortiss