8

私は2Dフラッシュマルチプレイヤーゲームとソケットサーバーを書いています。クライアントとサーバー間の移動アルゴリズムに関する私の当初の計画は次のとおりでした。

  • クライアントは、これらが変更されるたびに、プレーヤーの移動モード(前進または移動しない)とプレーヤーの回転モード(回転しない、左に曲がる、または右に曲がる)についてサーバーに通知します。
    • サーバーは数ミリ秒ごとにすべてのプレーヤーをループし、時間の差に基づいて回転角度と移動距離を計算します。同じ計算がクライアントによって行われます。

クライアントの現在の計算(サーバーでも同じ計算が使用されます)==>

旋回

var newTimeStamp:uint = UtilLib.getTimeStamp(); //set current timeStamp
                var rot:uint = Math.round((newTimeStamp - turningTimeStamp) / 1000 * 90); //speed = x degrees turning every 1 second
                turningTimeStamp = newTimeStamp; //update timeStamp
                if (turningMode == 1) //left
                {
                    movementAngle = fixAngle(movementAngle - rot);
                }
                else if (turningMode == 2) //right
                {
                    movementAngle = fixAngle(movementAngle + rot);
                }

private function fixAngle(angle:int):uint //fixes an angle in degrees (365 -> 5, -5 -> 355, etc.)
        {
            if (angle > 360)
            {
                angle -= (Math.round(angle / 360) * 360);
            }
            else if (angle < 0)
            {
                angle += (Math.round(Math.abs(angle) / 360) + 1) * 360;
            }
            return angle;
        }

動き

var newTimeStamp:uint = UtilLib.getTimeStamp(); //set current timeStamp
                var distance:uint = Math.round((newTimeStamp - movementTimeStamp) / 1000 * 300); //speed = x pixels forward every 1 second
                movementTimeStamp = newTimeStamp; //update old timeStamp
                var diagonalChange:Array = getDiagonalChange(movementAngle, distance); //with the current angle, howmuch is dX and dY?
                x += diagonalChange[0];
                y += diagonalChange[1];

private function getDiagonalChange(angle:uint, distance:uint):Array
        {
            var rAngle:Number = angle * Math.PI/180;
            return [Math.round(Math.sin(rAngle) * distance), Math.round((Math.cos(rAngle) * distance) * -1)];
        }

これはうまくいくようです。ラグを考慮に入れるために、サーバーはこのデータを送信することによってクライアントの情報を時々修正します。

このシステムでは、移動を処理するために使用される帯域幅はごくわずかです。ただし、サーバーとクライアントの座標および角度の違いが大きすぎます。ユーザーの待ち時間も考慮に入れるために、「アルゴリズム」を拡張する必要がありますか?または、優れたパフォーマンスを備えたクライアント<>サーバーマルチプレイヤーゲームの動きを処理するためのより良い方法はありますか?

4

3 に答える 3

6

私の最初の設計はあなたのものと似ていますが、それがうまくいかない場合は、おそらくクライアントにすべての動きをさせ、サーバーに範囲チェックをさせることができます.

したがって、最後に報告された位置が X である場合、次の位置は X から半径内にある必要があります。半径は、x、y データでクライアントから送信されたタイムスタンプの差に基づいています。

ほとんどの場合、これは不正行為を検出するために必要です。

停止、戦闘などには、攻撃とともに位置を送信する必要があり、位置によってトリガーされるアクションは、クライアントがその位置の更新を送信した後にのみトリガーされますが、サーバーベースになります.

これがあまり役立つかどうかはわかりませんが、最初のアルゴリズムから見られる衝撃的な再同期を停止する可能性があります.

コメント応答:

いいえ、クライアントはサーバーに位置を通知しますが、サーバーは次の位置を計算しようとしません。これは、サーバー (および他のすべてのクライアント) の位置が少なくとも 1 送受信サイクル遅れることを意味します。

クライアントにすべての作業を任せて、キャラクターがどこにいるかを把握し、サーバーに伝えるだけでいいと言っていると思いますが、サーバーがオプションで有効性をチェックして誰も不正行為をしていないことを確認できる十分な情報を含めてください。

チート検出は、パフォーマンスのためにオフにすることも、ランダムにチェックするように設定することもできます.

注: これを機能させるには、移動範囲内のオブジェクトのすべての衝突/位置情報をクライアントに送信する必要があります。

于 2009-06-30T20:14:00.537 に答える
1

これを行うには2つの方法が考えられます。クライアントにサーバーにコマンドを発行させると、サーバーが究極のマップキーパーになります。

または、マップをクライアントに保持します。クライアントは、移動を行うために「近くにある」他のクライアントとの接続を確立する必要があります。記録管理はサーバーによって行われ、数人のピア(ハッカー警察)によってチェックされます。

私にとって興味深いのは、ピア接続を監視する可能性であり、特定のしきい値を超える遅延があるピアはゲームに表示されません。

于 2009-06-30T23:51:56.900 に答える
0

サーバーが非常に遅いため、すべての動きを処理できませんか?特に2Dゲームでは?通常、小さな2Dゲームを作成すると、サーバーからすべての動きが返されるため、クライアントで計算する必要はありません。サーバーが遅れ始めた場合、私は単に少しフリーズします。これはとにかく通常予想されることです(ただし、これはほとんど発生しません)。

いずれにせよ、クライアントが実際に計算を行わなくても、パフォーマンスがどのようになるかは間違いなくわかります。パフォーマンスが十分でない場合は、サーバー上のプレーヤーの動きをループすることで遅延が発生していないかどうかを確認します(クライアントごとに異なるスレッドの使用を開始します)。

帯域幅に実際の制限がある場合(動き自体はほとんどデータを渡さない)、確かにその特定のユーザーの平均遅延を見つけて、それをアルゴリズムに計算する必要があります。ただし、(精度のために)平均を継続的に検出するには、サーバーにpingを実行してラウンドトリップ時間を検出する必要がありますが、これはそれほどコストがかかることではありません。

于 2009-06-30T20:09:28.050 に答える