2017-03-05 9 views
1

私は現在、(ゲーム体験を学ぶための)ユニティゲームのための自分のネットコードを構築しています。私は物事の「デコードパケット」側で深刻な遅れに走っています。マルチプレイヤーゲームでは、効率的に位置データをソケットに送信する方法はありますか?

基本的には、自分の位置データ(Vector3(x、y、z))をJSON文字列としてサーバーに送信し、サーバーはそれを他のすべてのプレイヤーに送信します(playerObject)。

物のソケット側はうまく動きます。パケットが作成されてからパケットが受信されるまでの遅延はごくわずかです。

しかし、彼らは非JSONへのリモートクライアントの位置をしようとしているとき、私はは私のクライアントの大規模な遅延を取得しています:

Vector3 remotePos = JsonUtility.FromJson<Vector3>(_command.Substring(5 + _usernameLength));

JSON文字列がに、文字列の先頭に識別子を持っています位置の更新であり、次にユーザー名の長さを示す2つの数字、次にユーザー名(リモートクライアントが適切なplayerObjectを更新できるように)が続きます。

POS09NewPlayer{"x":140.47999572753907,"y":0.25,"z":140.7100067138672}

サーバーからそのようなパケットを受信した後、私のクライアントは、次の作業プリフォームます:

 int _usernameLength = Int32.Parse(_command.Substring(3, 2)); 
     string _username = _command.Substring(5, _usernameLength); 
     Vector3 remotePos = JsonUtility.FromJson<Vector3> 
     if (_username != username) 
     { 
     playerDict[_username].transform.position = remotePos; 
     } 

この「作品」のすべてを、ちょうど3のクライアントが同時に接続した後、非常に低迷取得します。

私は間違っていますか? 3人のプレイヤーに対して0.115秒ごとに更新情報を送信しているので、重大な欠陥が存在しなければなりません。バトルフィールドのようなゲームでは、64人のプレイヤーに対して60個のアップデートを送ることができます。

アドバイスをいただければ幸いです。

+1

少なくとも 'JsonUtility.FromJson'を' if'内に移動します –

+0

私はこのケースでこのような巨大な影響を引き起こす可能性が非常に高いです。 – Evk

+0

@Evk json'dパケットを数えながら受信パケットを数えています。私は約3倍の速さでパケットを受信して​​います。つまり、物事は後ろに落ちる。 – MrDysprosium

答えて

5

もちろん、最適化の余地はあります。大きなゲームエンジンをリファレンスとして引用しているので、古いUnreal Engineのバージョンと使用している最適化のいくつかの例を紹介します。

  • ネットワークパッケージはUDPプロトコルを使用します。それでも、ドロップされたパッケージ、重複したパッケージ、または順序が乱れたパッケージを単独で処理する必要がありますが、実際のTCP接続を使用するのではなく、その苦いピルを飲み込むことになります。
  • サーバーは、クライアントに送信した情報更新を追跡します。サーバーによって複製されるクライアント側のオブジェクトごとに、サーバーはすべての変数を追跡します。各ゲームループ更新の最後に、サーバは、サーバがクライアントに更新を最後に送信したときと実際に異なる値を有する変数をチェックする。実際に差がある場合にのみ、新しい値がクライアントに送信されます。それは信じられないほどのオーバーヘッドのように見えるかもしれませんが、ネットワーク帯域幅は、システムのメモリやCPU時間よりもはるかに不十分なリソースです。
  • ベクトル情報は実際にはネットワーク上で送信される前に切り捨てられます。エンジンはベクトル要素のデータ型としてfloatを使用しますが、X、Y、Zを最も近い整数に丸めて、完全な浮動小数点データの代わりにそれらを送信します。そうすれば、圧縮されていない元のフロートの12バイトではなく、数バイトから数バイトになります。
  • 位置の更新は、クライアント側でシミュレートされ、サーバーからの受信データとマージされます。位置更新によるジッタを避けるために、クライアントは速度値からオブジェクトの新しい位置を予測します。クライアントが後でサーバーから位置更新を受け取ると、オブジェクトは新しい位置(基本的にはクライアントとサーバーの座標の間の妥協点)にわずかに移動し、サーバーの位置がサーバーの位置と大きく異なる場合は、クライアントのバージョン。これは多くのことで行われます。プレイヤーが発射物を発射すると、その発射がサーバー上で実行され、発射物が生成されてプレーヤーに送信され、その位置が更新されます。しかし、プレイヤーはショットについての関数呼び出しを受け取り、ローカルにプロジェクトを作成し、その軌道を更新します。たとえその発射物が実際にクライアント側のプレーヤーを殺すことができないとしても、滑らかなゲームプレイの印象を与えるためにその軌道と効果をローカルでシミュレートすることができる。ヒットした場合、サーバーがクライアントにそのような効果を作成するよう指示することなく、適切な効果をその場所で再生することができます。
  • サーバーは、各プレーヤーに関連するものを追跡します。プレイヤーが複数の壁の裏側の地図の反対側にいる場合は、そのプレイヤーのアクションについての更新を送信する必要はありません。そのプレイヤーの発射物が後であなたの視野に入ると、サーバは適切な時間にそれらの発射物についてあなたにまだ伝えることができます。

全体的には、この記事に詰め込むことはほとんどできませんが、ネットワークの帯域幅はマルチプレイヤーゲームの中で最も限られた資源であるため、それは逃げることのできる情報パッケージをほとんど、少ししか送信しません。

お知らせ位置ベクトルの1つのコンポーネントよりも小さいものは、すでにこのエンジンのベクトル全体に対して大きすぎると考えられます。私は、JSONが実際にはその冗長さのために、ここでいくつかのオーバーヘッドを実際に導入していると思います。実際のビットを送信し、その意味を実際のパッケージから推測することができるときには、数字を文字列として送信しています。

+0

うわー、お書き添えいただきありがとうございます...役に立つ情報がたくさんあります。 最後の部分について少し詳しく説明できますか? "あなたは実際のビットを送信し、実際のパッケージからその意味を推測することもできます。" – MrDysprosium

+0

JSONを使用していない可能性が高いため、実際のエンジンが実際にどのように動作しているかのヒントになりました。 UDPのように何かをベアボーンとして扱う場合は、任意のバイトを自由に送ることができます(パッケージあたり最大約65000バイトまで)。次に、プレーヤを識別するためのバイトをいくつか、送信されるデータを識別するためのもの、ベクトルの実際の数値のためのもの、クライアント上で自分自身を解析するものがあります。 .NETのUDPの例:https://social.msdn.microsoft.com/Forums/en-US/92846ccb-fad3-469a-baf7-bb153ce2d82b/simple-udp-example-code?forum=netfxnetcom –

+0

UDPはそれ自体で重複、欠落、または順序のずれたパッケージを処理しないので、あなた自身でそれを処理する必要があります。これは、パッケージが受信されたことを確認する何らかの形式の通知を送信することを意味し、そうでない場合は、確認応答が受信されるまで、定期的な間隔でパッケージを送信します。また、送信パッケージのタイムスタンプを付けておくと、新しいデータがあらかじめ到着した場合に古いデータを受信側にドロップすることができます(ただし、送信者はこれらのパッケージを送信しないように確認を送信します)。 –

関連する問題