0

私はマルチプレイヤーフラッシュゲームに取り組んでいます。サーバーは、各クライアントに、プレーヤーの近くにいる他のプレーヤーを通知します。これを行うには、サーバーはどのクライアントが互いに近くにあるかを継続的にチェックする必要があります。以下は、一時的な解決策として、現時点で私が使用しているものです。

private function checkVisibilities()
{
    foreach ($this->socketClients as $socketClient1)
    { //loop every socket client
        if (($socketClient1->loggedIn()) && ($socketClient1->inWorld()))
        { //if this client is logged in and in the world
            foreach ($this->socketClients as $cid2 => $socketClient2)
            { //loop every client for this client to see if they are near
                if ($socketClient1 != $socketClient2)
                { //if it is not the same client
                    if (($socketClient2->loggedIn()) && ($socketClient2->inWorld())
                    { //if this client is also logged in and also in the world
                        if ((abs($socketClient1->getCharX() - $socketClient2->getCharX()) + abs($socketClient1->getCharY() - $socketClient2->getCharY())) < Settings::$visibilities_range)
                        { //the clients are near each other
                            if (!$socketClient1->isVisible($cid2))
             { //not yet visible -> add
                                 $socketClient1->addVisible($cid2);
                            }
                        }
                        else
                        { //the clients are not near each other
                            if ($socketClient1->isVisible($cid2))
                            { //still visible -> remove
                                $socketClient1->removeVisible($cid2);
                            }
                        }
                    }
                    else
                    { //the client is not logged in
                        if ($socketClient1->isVisible($cid2))
                        { //still visible -> remove
                            $socketClient1->removeVisible($cid2);
                        }
                    }       
               }
         }
     }
}

正常に動作します。しかし、これまで私は一度に2人のプレイヤーとしかプレイしていません。この関数は、すべてのクライアントのすべてのクライアントをループしています。したがって、100人のプレーヤーでは、関数が実行されるたびに100 * 100=10.000ループになります。これは、それを行うための最良または最も効率的な方法ではないようです。

さて、皆さんは私の現在の設定についてどう思いますか、そしてこれらの可視性を処理するためのより良い方法について何か提案がありますか?

更新:私は世界が無限であることを言及するのを忘れました。それは実際には「宇宙」です。地図はありません。また、2次元(2D)ゲームです。

前もって感謝します。

4

3 に答える 3

4

私が最初に言うことは、あなたのコードが裏返しに見えるということです。どのクライアントがログインしていて、世界中にいるのかをチェックするといううんざりするような作業をしなければならない高レベルのゲームロジック機能があるのはなぜですか?より高いレベルで実行され、ゲーム内ロジックが現在プレイしているプレーヤーと世界中のプレーヤーのみを処理できるように、ネットワーク関連のものはすべてゲームロジックから削除する必要があります。これはあなたに簡単な質問を残します:これらの2人のプレーヤーはお互いに十分に近いですか?すでにお持ちのように、ここでは簡単な距離チェックで十分です。

次のことはあなたがするループの量を減らすことです。距離は一般に可換特性であるため、AとBの間、およびBとAの間の距離を確認する必要はありません。これを行うには、最初のループがすべてのクライアントを通過するのに対し、2番目のループは反復するだけで済みます。最初のクライアントの後に来るすべてのクライアント。これにより、実行する必要のある反復回数が半分になります。

あなたが述べているように、あなたはこれを継続的に行う必要もありません。ゲームがスムーズに実行されるように、十分な頻度で実行する必要があります。移動速度がそれほど速くない場合は、数秒ごとにこれを実行するだけで十分です。

それでも十分でない場合は、ianhで説明されているような空間ハッシュシステムが、実行するクエリの数を減らすための良い方法です。グリッドが最も簡単ですが、ある種のツリー構造(理想的には自己バランス)は別のオプションです。

于 2009-10-26T10:44:27.797 に答える
3

最も簡単な解決策は、次のように、世界を均一なグリッドに分割することです。

_|____|____|____|_
 |    |    |    |
_|____|____|____|_
 |    |    |    |
_|____|____|____|_
 |    |    |    |
_|____|____|____|_
 |    |    |    |

次に、オブジェクトが交差するグリッドタイルにオブジェクトを挿入します。

_|____|____|____|_
 | @  |    |    |
_|____|____|____|_
 |    |d d |    |
_|____|____|____|_
 |    | d  |  d |
_|____|____|____|_
 |    |    |    |

ここで、近くのオブジェクトのクエリを実行するには、近くのセルを確認するだけで済みます。たとえば、プレーヤー(@)から1つのタイル内に誰がいるかを確認するには、マップ全体ではなく、9つのタイルをチェックインするだけで済みます。

/ | //// | //// | ____ | _
/ | / @ // | //// | |
/ | //// | //// | ____ | _
/ | //// | d / d / | |
/ | //// | //// | ____ | _
 | | d | d |
_ | ____ | ____ | ____ | _
 | | | |

ただし、世界によっては、この手法は非常に無駄になる可能性があります。空のセルが多数存在する可能性があります。これが問題になる場合は、より複雑な空間インデックスを実装することをお勧めします。

于 2009-10-26T10:09:59.137 に答える
2

四分木を使用してプレイヤーの位置を表現してみてください。
このウィキ記事はこちらです。
それが行うことは、必要なだけスペース (プレーン) を分割するツリー内のスペース (ユーザー) に指定したオブジェクトを保持することです。無限の問題については、プログラミングには実際に無限のものはないため、ユーザーが通過できない境界を定義します(座標の非常に大きな数でも、ユーザーが到達するのに100年かそこらかかります) .

于 2009-10-26T10:43:56.970 に答える