0

我正在开发一款多人 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);
                        }
                    }       
               }
         }
     }
}

它工作正常。然而,到目前为止,我一次只和两个玩家一起玩。此函数为每个客户端循环每个客户端。因此,对于 100 名玩家,每次运行该函数时将有 100 * 100 = 10.000 次循环。这似乎不是最好或最有效的方法。

现在我想知道你们对我目前的设置有什么看法,以及你们是否有任何关于更好地处理这些可见性的建议。

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

提前致谢。

4

3 回答 3

4

我要说的第一件事是你的代码看起来是由内而外的。为什么你有一个高级的游戏逻辑函数,它必须完成检查哪些客户端已登录和在世界上的繁重工作?应该从游戏逻辑中删除所有网络内容,以便在更高级别上完成,并且游戏内逻辑只需要处理当前正在玩的玩家和世界上的玩家。这给您留下了一个简单的问题:这 2 名球员之间是否足够接近?正如您已经拥有的那样,一个简单的距离检查就足够了。

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

正如您所说,您也不必连续​​执行此操作。你只需要经常这样做,以确保游戏顺利运行。如果移动速度不是那么高,那么您可能只需要每隔几秒钟执行一次,它就足够好了。

如果这对您来说仍然不够好,那么 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

尝试使用四叉树来表示玩家的位置。
wiki 文章在这里
它所做的是将您提供给它的对象保留在树中的空间(用户)中,该树根据需要对空间(平面)进行分区。至于无穷大问题 - 编程中没有什么是真正无限的,所以定义一个用户不能通过的边界(即使是一个非常大的坐标数,用户需要 100 年左右才能到达) .

于 2009-10-26T10:43:56.970 回答