如何让服务器以有效的方式告知游戏客户有关其他附近可见玩家的信息?

时间:2009-10-26 09:58:09

标签: client-server visibility multiplayer

我正在开发一款多人Flash游戏。服务器通知每个客户端其他玩家在玩家附近。为此,服务器必须连续检查哪些客户端彼此靠近。以下是我目前使用的,作为临时解决方案:

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个循环。这似乎不是最好或最有效的方法。

现在我想知道你们对我目前的设置有什么看法,以及你是否有更好的方法来处理这些可见性。

更新:我忘了提到世界是无限的。它实际上是“宇宙”。没有地图。此外,它是一个二维(2D)游戏。

提前致谢。

3 个答案:

答案 0 :(得分:4)

我要说的第一件事是你的代码从里到外看。为什么你有一个高级游戏逻辑功能,必须做的工作是检查哪些客户端登录和在世界上?应该从游戏逻辑中删除所有网络内容,以便它在更高级别上完成,并且游戏内逻辑只需要处理当前正在玩的和世界上的玩家。这给你留下了一个简单的问题:这两个玩家是否足够接近?这里只需要一个简单的距离检查就足够了。

接下来就是减少你做的循环量。距离通常是一个可交换的属性,因此您不需要检查A和B之间以及B和A之间的距离。为此,当您的第一个循环遍历所有客户端时,第二个循环只需要迭代所有在第一个之后来的客户。这会使您需要执行的迭代次数减少一半。

你也不必像你所说的那样不断地这样做。你必须经常这样做,以确保游戏顺利运行。如果移动速度不是那么高,那么你可能每隔几秒钟就必须这样做才能足够好。

如果这对你来说仍然不够好,那么ianh所描述的某种空间散列系统是减少你所做查询次数的好方法。网格是最简单的,但某种树结构(理想情况下是自平衡)是另一种选择。

答案 1 :(得分:3)

最直接的解决方案是将世界划分为统一网格,如下所示:

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

然后将对象插入到它们相交的任何网格图块中:

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

现在要对附近的对象进行查询,您只需要查看附近的单元格。例如,要查看来自播放器(@)的一个磁贴中的哪个人,您只需要签入9个磁贴,而不是整个地图:

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

然而,根据您的世界,这种技术可能非常浪费:可能会有很多空单元格。如果这成为问题,您可能希望实现更复杂的spatial index

答案 2 :(得分:2)

尝试使用四叉树来表示玩家的位置 维基文章为here 它的作用是将您在空间(用户)中提供的对象保存在树中,该树根据需要对空间(平面)进行分区。 至于无限问题 - 编程中没有任何东西真的是无限的,所以定义一个不能被用户传递的边界(即使是一个非常大的数字用于坐标,这将需要用户100年左右才能到达)