8

マルチプレイヤー ゲームに取り組んでいますが、プレイヤーの同期に問題があります。

プレーヤーが移動キー (W、A、S、D) のいずれかを押すと、クライアントは押されたボタンに関するパケットを送信し、サーバーは押されたキーに従って速度を設定し、近くにいるすべてのプレーヤーに新しい速度を送り返します。

プレーヤーがキーを放すと、クライアントはパケットを送信し、サーバーはプレーヤーの速度を 0,0 に設定し、位置と速度を近くのすべてのプレーヤーに送信します。

問題は、キーを放すと、ほとんどの場合プレーヤーが元に戻ることです。

どうすればこれを修正できますか?

私はsocket.ioを使用しています。

クライアント側:

   socket.on('positionEntity', function (data) {
        console.log((data.x - entities[data.id].x)+" "+(data.y - entities[data.id].y));
        entities[data.id].setPosition(data);
    });

    $(document).keyup(function(e) {
        if (e.keyCode == 87) {
            keys.W = false;
            socket.emit("stopMove", {dir: 0, time: Date.now()});
        }

        if (e.keyCode == 65) {
            keys.A = false;
            socket.emit("stopMove", {dir: 1, time: Date.now()});
        }

        if (e.keyCode == 83) {
            keys.S = false;
            socket.emit("stopMove", {dir: 2, time: Date.now()});
        }

        if (e.keyCode == 68) {
            keys.D = false;
            socket.emit("stopMove", {dir: 3, time: Date.now()});
        }
    });

    $(document).keydown(function(e) {
        if (e.keyCode == 87 && !keys.W) {
            keys.W = true;
            socket.emit("startMove", {dir: 0, time: Date.now()});
        }

        if (e.keyCode == 65 && !keys.A) {
            keys.A = true;
            socket.emit("startMove", {dir: 1, time: Date.now()});
        }

        if (e.keyCode == 83 && !keys.S) {
            keys.S = true;
            socket.emit("startMove", {dir: 2, time: Date.now()});
        }

        if (e.keyCode == 68 && !keys.D) {
            keys.D = true;
            socket.emit("startMove", {dir: 3, time: Date.now()});
        }
    });

サーバ側:

socket.on('startMove', function(data) {
    if (data.dir == 0) socket.player.setMotionY(-5);
    if (data.dir == 1) socket.player.setMotionX(-5);    
    if (data.dir == 2) socket.player.setMotionY(5);
    if (data.dir == 3) socket.player.setMotionX(5);

    io.sockets.emit("positionEntity", socket.player.serializePosition());
});

socket.on('stopMove', function(dir) {
    socket.player.setMotionX(0);
    socket.player.setMotionY(0);

    io.sockets.emit("positionEntity", socket.player.serializePosition());
});
4

1 に答える 1

16

これはあなたが取り組んでいる非常に複雑なタスクであり、私はペット プロジェクトの一環として行ったものです ;)

あなたはクライアント サーバー アーキテクチャのゲームに取り組んでいるため、サーバーがゲームのロジックと決定に関する最終的な権限を持っています。現在レンダリングを処理している方法では、遅延のために速度と方向が急激に変化します (お気づきのとおりです!)。

秘訣は、リモート プレーヤーの動きの情報をバッファリングして、プレーヤーを常にわずかな遅延でレンダリングすることです。プロジェクトでは原始的なものを維持し、加速度や速度ではなく、位置データのみを使用しました。例として、プレイヤー A が自分のマシン上で移動すると、確認応答を受信するためのコマンドが即座に送信されません。彼は移動し、ネットワーク送信ループの次のティック (1 秒あたり 10 ティック) で、彼の位置がサーバーに送信され、サーバーはサーバー内のすべてのクライアントを更新します。この新しい位置の近く。これらのクライアントには、更新をレンダリングする前に、各位置を一定時間 (100 ミリ秒) 格納する「リモート」プレーヤーごとにバッファがあります。

クライアント コードの BASIC 補間関数。このシステムは、リモート プレーヤーごとに最大 2 つの更新のみをキューに入れました。更新配列のインデックス 0 は 2 つのうち古い方でした。したがって、インデックス 0 はリモート プレーヤーの位置 0ms であり、インデックス 1 は 100ms でのリモート プレーヤーの位置です。

interpolate: function() {
  var timeDifference = new Date().getTime() - this.serverUpdates[1].time;
  // Percentage of time passed since update was received (I use 100ms gaps)
  var interPercent = (timeDifference) / 100;

  // Latest updates (index 1 is the newest state)
  var s1 = this.serverUpdates[0],
    s2 = this.serverUpdates[1];

  // Need to lerp between values provided in latest update and older one
  var p = (new Vector3(s2.position)).subtract(new Vector3(s1.position));
  p = p.timesScalar(interPercent);

  // New position is the older lerped toward newer position where lerp 
  //percentage is the time passed 
  this.position = new Vector3(s1.position).add(p);

  // Now update rotation in a smooth manner
  var rotationDifference = (s2.rotation - s1.rotation);
  if (rotationDifference && rotationDifference != 0) {
    this.rotation = s1.rotation + (rotationDifference * interPercent);
  }
},

そのコードでは、約 100 ミリ秒離れた更新を受信して​​いたので、時刻 0 の位置は s1 で、時刻 100 ミリ秒の s2 は位置です。したがって、s2 を受信して​​から 50 ミリ秒が経過した場合、エンティティは 2 つの位置の間で 50% になります。これは私のニーズには問題ありませんでしたが、他のタイプのゲームではうまくいかないか、微調整が必​​要な場合があります.

これらのリソースは、ネットワーク化されたゲームと遅延への対処を説明するための優れた出発点です。リモート クライアントでのゲームの滑らかさに内挿と外挿の実装の違いに驚かれることでしょう。

http://gafferongames.com/networking-for-game-programmers/what-every-programmer-needs-to-know-about-game-networking/

https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization <- 本当に良い!

https://developer.valvesoftware.com/wiki/Lag_compensation

幸運を :)

于 2013-08-22T21:09:25.980 に答える