1

単純なクライアント <> サーバー マルチプレイヤー ゲーム用の単純なサーバーを作成していたとき、翻訳ライブラリを使用して次のテキスト ベースのプロトコルを考えました。基本的に、各コマンドには特定の意味がありました。たとえば、次のようになります。

1 = character starts turning right
2 = character starts turning left
3 = character stops turning
4 = character starts moving forward
5 = character stops moving
6 = character teleports to x, y

そのため、クライアントは単純に次のようにブロードキャストして、プレーヤーが現在前進して右に曲がっていることを通知します。

4
1

または、100x200 にテレポートするには:

6#100#200

# はパラメーター区切り文字です。

ソケット接続はプレーヤー識別子に接続されるため、メッセージがどのプレーヤーに属しているかを知るために識別子をプロトコルでブロードキャストする必要はありません。

もちろん、すべてのデータはサーバー側で検証されますが、それは別の主題です。

さて、これは私には非常に効率的であるように思えます。私が前進して右折していることをサーバーに通知するのにわずか 2 バイトです。

ただし、私が見たほとんどの「プロフェッショナル」なコード スニペットは、オブジェクトまたは xml コマンドを送信しているように見えました。これには、より多くのサーバー リソースが必要なようですね。

テキストベースのプロトコルが効率的である理由についての私の未経験の論理には欠陥がありますか? または、リアルタイム アクション マルチプレイヤー ゲームの推奨プロトコルは何ですか?

複数のクラスター/サーバーを使用して 2D マルチプレイヤー ゲームの過剰な帯域幅をカバーしたり、安全な同期の問題や煩わしさを回避したりしたくないため、できるだけ効率的なプロトコルをセットアップしたいと考えています。

4

4 に答える 4

4

ただし、私が見たほとんどの「プロフェッショナル」なコード スニペットは、オブジェクトまたは xml コマンドを送信しているように見えました。これには、より多くのサーバー リソースが必要なようですね。

テキストベースのプロトコルが効率的である理由についての私の未経験の論理には欠陥がありますか? または、リアルタイム アクション マルチプレイヤー ゲームの推奨プロトコルは何ですか?

プレーン テキストは、同じ情報を含むバイナリ形式よりも送信コストが高くなります。たとえば、1 バイトだけを送信する場合、0 ~ 9 の数字の 10 個の異なるコマンドしか送信できません。256.

そのため、オブジェクトは大きいと考えていますが、実際には、ほとんどの場合、同じオブジェクトのプレーン テキスト表現よりも小さくなっています。多くの場合、それらは圧縮なしで可能な限り小さくなっています (また、いつでも圧縮を追加できます)。

プレーン テキスト形式の利点は、デバッグと理解が容易なことです。残念ながら、独自のエンコーディングをそこに入れると、これらの利点が失われます (たとえば、コマンドを読み取り可能な名前ではなく 1 桁に減らす)。欠点は、フォーマットが大きくなり、独自のパーサーを作成する必要があることです。XML フォーマットは 2 番目の問題を解消しますが、純粋な効率性でバイナリ フォーマットと競合することはできません。

ただし、この段階ではおそらくこの問題について考えすぎているでしょう。上記のコマンドなどのイベントに関する情報のみを送信する場合、帯域幅は問題になりません。ゲームの状態に関する情報をブロードキャストしているため、コストが高くなる可能性がありますが、送信先と送信頻度に注意することで軽減できます. これは問題が最も少ないため、今のところ最も簡単な形式で作業することをお勧めします。必要に応じて、メッセージの書き込みルーチンと読み取りルーチンを後で変更できる状態に、コードが常にあることを確認してください。

于 2010-05-05T16:29:49.050 に答える
4

データの送信に伴うレイテンシに注意する必要があります。これらのパケットの受信間の時間が送信間の時間と異なる場合、「回転の開始」/「回転の停止」はあまり効果的ではありません。

すべてのゲームについて話すことはできませんが、この種のコードに取り組んだときは、方向と位置の情報をネットワーク経由で送信していました。そうすれば、受信者は平滑化と外挿を行うことができます(すでに古いことがわかっているデータに基づいて、オブジェクトが「現在」あるべき場所を見つけます)。ゲームごとに異なるデータを送信する必要がありますが、一般的に言えば、受信者のデータ表示を送信者の表示と一致させる方法を理解する必要があるため、ネットワークの問題に直面しても回復力のあるデータを送信する必要があります。

また、多くのゲームでは、この種のデータ転送に TCP ではなく UDP を使用しています。UDP は信頼できないため、すべてのパケットを取得できない場合があります。つまり、「今すぐ移動を停止する」または「今すぐ移動を開始する」は、ペアで受信されない場合があります。UDP の上にコーディングする場合、クライアントが同期する十分な機会を得るために、「これが現在の状態です」を頻繁に送信することがさらに重要です。

于 2010-05-04T17:51:55.540 に答える
3

一般的な方法は、テキストや xml ではなく、バイナリ形式を使用することです。したがって、たった 1 バイトで、256 の異なるコマンドの 1 つを表すことができます。

また、TCP ではなく UDP を使用します。UDP を使用すると、パケット損失が発生した場合に、ゲームの応答性が大幅に向上します。パケット損失の場合でも、動きを推測できます。各パケットでパケット番号を送信して、コマンドがいつ送信されたかをサーバーが認識できるようにします。

最新のマルチプレイヤー ゲームでのネットワーク プログラミングについて詳しく学べるQuake ソース コードをダウンロードすることを強くお勧めします。とても読みやすく、理解しやすいです。

編集:

私はほとんど忘れていました.. Google のProtocol Buffersは、複雑なデータ構造を送信するときに非常に役立ちます。

于 2010-05-04T18:30:10.780 に答える
1

私は 2 セントを差し出して、バイナリ シリアライゼーションと呼ばれるものへの実用的なアプリケーションを提供しようと考えました。コンセプトは実際には信じられないほどシンプルですが、外見だけでは複雑に見えます。

実際に XML を送信し、XML 内のデータをサーバー自体内のさまざまな機能に処理するサーバーを持つことができます。サーバー内に変数として格納されている単一の数値をサーバーに送信することもできます。その後、残りのデータを処理し、正しい一連のアクションを選択できます。

例として、いくつかの大まかなコード:

private const MOVE_RIGHT:int = 0; 
private const MOVE_LEFT:int = 1;
private const MOVE_UP:int = 2;
private const MOVE_DOWN:int = 3;

function processData(e:event.data)
{
    switch (e)
    {
       case MOVE_RIGHT:
       //move the clients player to the right

       case MOVE_LEFT:
       //move the clients player to the left

       case MOVE_UP:
       //move the clients player to the up

       case MOVE_DOWN:
       //move the clients player to the down

    }
}

これは非常に単純な例であり、変更する必要がありますが、ご覧のとおり、数値の文字列で送信する整数でエンコードされた変数を格納するだけです。これらを解析し、情報のヘッダーを作成して、送信する必要があるデータのさまざまなセクションに編成できます。

また、パケットが欠落しただけでゲーム体験が妨げられるべきではなく、クライアント側とサーバー側で処理できる必要があるため、ゲーム用に UDP セットアップを行うことをお勧めします。

于 2011-06-21T06:57:31.653 に答える