完全な状態の更新よりも効率的にマルチプレイヤーゲームの状態を同期するにはどうすればよいですか?


10

私は以前に少しゲームネットワークコーディングを行いましたが、主にリアルタイムニーズのないゲームのTCPを使用しました。ネットワーク化されたマルチプレイヤーで2D Javaゲームに取り組んでいます。学習のために、私はこれを既存のネットワークAPIなしで自分で行いたいと思っています。

サーバーからクライアントに送信されるゲームの状態を効率的に表すにはどうすればよいですか?最も明白ですが、おそらく最も効率の悪い方法があります。これは、各プレーヤーの場所、アニメーションの状態などを使用してゲーム状態コンテキストオブジェクトを作成し、更新ごとにそれを各プレーヤーに送信することです。それを実装することはそれほど難しくはないように見えますが、おそらくリアルタイムの相互作用に近いものを達成するには大きすぎるでしょう(もちろん、これに関する私の経験は限られているため、私は正しくない可能性があります)。

状態の変化のみを送信するために以前に使用した確かな方法はありますか?パフォーマンスに十分な格差があっても、追加の作業に値するでしょうか?


2
すべてのフレームをフル状態で試してみて、遅すぎる場合(やや単純な2Dゲームの場合は、おそらく十分効率的です)、最適化を試みます。正常に機能する場合は、正常に機能し、後でネットワークがボトルネックになっていることに気付かない限り、変更する必要はありません。
Robert Rouhani、2012年

回答:


10

完全なゲーム状態を定期的に送信することは、ゲームの複雑さに大きく依存しますが、通常は実行できません。小さなワールドモデルを使用した単純なゲームの場合は、機能する可能性があります。

私は個人的に次のモデルではるかに成功しました:

  • 空間データ構造の明確に定義されたオブジェクトモデル(オクツリーなど)に格納されたゲームの状態
  • ゲームの状態へのすべての変更(クライアントまたはサーバー上で)は、イベントとして説明されます。イベントには、ゲームオブジェクトのプロパティの変更、マップタイルの変更、ゲームオブジェクトの動きなどがあります。
  • サーバー上のゲームエンジンは、ゲームが進行するにつれてイベントのストリームを生成します。これらはサーバーのゲーム状態に直接適用されます。
  • イベントはプレーヤーにも送信されますが、イベントがそのプレーヤーに関連している場合のみです(たとえば、現在の位置からイベントが表示されますか?)
  • プレーヤーの可視性が変化すると、プレーヤーが移動したときに、マップの新しい部分などを「明らかに」するイベントが発生する場合があります。これは、プレーヤーが最初にゲームに参加したときに、関連するゲームの状態の正確な初期ビューをプレーヤーが確実に取得するためにも使用できます。
  • プレーヤーのゲームの状態は、受信したイベントで更新されます。そのため、ゲームの状態の部分的なモデルしかありませんが、すべてのイベントが正しく処理されることを前提として、サーバーとの同期を維持する必要があります

これにより、非常に大きなゲームの世界でも、優れたパフォーマンスが得られました。

もう1つのヒントは、サーバーに関係なくクライアントがアニメーションやパーティクルエフェクトなどを処理できるようにすることです。これらを送信する意味はありません。適切なゲームイベントによって「トリガー」される必要があるだけです。


6

同期は通常、増分と絶対の2つの部分に分かれています。

時にはすべてを送信する必要がありますが、それは大きいですが、正しい方法でパックすると、数秒ごとにこれを実行できます。インクリメンタルリフレッシュの障害を修正し、エブリシングを導入することは良いことです。

リアルタイムのエクスペリエンスを実現するには、いくつかの変更をすばやく送信する必要がありますが、変更できるのは属性のみです。たとえば、ロケットが直線で飛行する場合、位置を更新する必要はなく、各クライアントは開始点から位置を計算できます。しかし、それがヒットすると、それについてのメッセージを生成する可能性があるため、各クライアントはロケットを適切な場所で爆発させることができます。小さな不具合は無視できます。

もちろん、クライアントに影響を与える可能性がある場合は、更新のみを行います。画面から遠く離れたものは価値がありません。一部の値はそれほど頻繁に更新できません。たとえば、位置は多かれ少なかれ正確であることが重要です。イベント(死、発砲、爆発など)は即座に送信する必要がありますが、直接重要ではない値は、スコアボード、チャットなどの更新間隔を短くすることができます。

データのパッキングも重要です。1つのUDPパッケージで約1400バイト(構成に依存。これはデフォルトです)を送信できます。通常、ヘッダーは数バイトあります。したがって、1つのパッケージで50-100ユニットの位置を簡単に更新できます。


アドバイスMatziをありがとう。私はまだサーバーとクライアントの実装に取り​​組んでいますが、数日後にもう一度確認し、おそらくあなたの答えを受け入れます。
ハズ

頑張って!;)
Matzi

1

ゲームによっては、キーボード/ジョイスティック入力やタイマーイベントなどの非決定的な入力を共有するだけで、各クライアントが偶然同じゲームをプレイする「同期実行」モデルを検討する場合があります。(各クライアントがローカルシミュレーションを実行し、リモートシミュレーションの結果を統合することを期待するモデルとは異なります)。これが機能するためには、通常、ゲームエンジンが完全に確定的である必要があります。これは、ゲームによっては大きな負担になる可能性があります。しかし、ゲームがすでに確定的である場合、これはより簡単なアプローチかもしれません。

この#AltDevBlogADayの投稿では、最近のRTSでのこのアプローチのいくつかの側面について説明します(具体的には、クライアントが「異なる」ゲームの実行を開始するタイミングを検出する方法)。

ただし、別の方法で証明されるまでは、シンプルにしてください。:)


1
これらは、このアプローチを使用するFactorioの開発者からの優れた読み取りであり、このアプローチの複雑さを示唆していますが、それが実行可能であることも示しています:factorio.com/blog/post/fff-76 factorio.com/blog/post/fff -147 factorio.com/blog/post/fff-188
AaronLS
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.