随机地图生成器 - 在网格上创建区域

时间:2012-03-05 09:46:36

标签: php mysql random

我正在开发一款需要随机生成地图的游戏。有效地,地图将是一个巨大的网格,其中包含散布在各个区域的对象,这些网格主要是空虚。我的想法是,我首先生成这些区域,然后为每个区域类型的各个类处理区域内地图的生成。

我目前要做的是在网格上随机生成这些区域。区域将始终为矩形或正方形,任何大小,网格本身也可以是任何大小(同样,矩形或方形)。

因此,为了简化所有这些,我试图在任意大小的网格上生成随机比例的矩形。作为记录,当我说任意时,我的意思是非常大 - 我们可能会看到高达100,000 x 100,000的尺寸。区域可能最多为100x100,但同样,脚本应该能够应对任何大小。

只是为了抛出更多的约束,这些区域不能重叠。最终,区域和每个区域内生成的对象都将被放入MySQL数据库中。

我最初认为使用二维数组来表示整个网格,并简单地将空间标记为内部空间就可以了,并且它是针对小尺寸网格的初始测试。我发现对于非常大的网格,Php抱怨超出内存限制并且不会执行脚本。

我考虑过但尚未尝试的另一种方法是在创建数据库时将区域插入数据库,然后在数据库上运行查询,以便在每次需要时查看区域是否为空。我相信我可以做到这一点,但数据库查询的数量将是巨大的。通过纯粹的数学方法,我可以通过消除某些可以确定无法使用的方格来减少所需的测试次数,但对于大型网格,我们仍然在谈论大量的查询。这会让剧本真的非常耗费时间,我不禁觉得这是不必要的。如果可能的话,我宁愿以另一种方式做事。

我想到的最后一种方法纯粹是数学方法,如果能使它成功,那将是完美的。我只使用了两个变量 - 最大x和最大y来存储每个轴上的最高值。在测试创建区域时,我只是检查新区域的左上角坐标是否低于最大x和y - 如果是,则无法使用该空间。如果任何一个更高,则没有问题,并且该区域已创建。你们中的一些人可能会发现我想象中的问题,但是长话短说,在某些情况下,这个系统会判断一个空白区域是无法使用的,所以当我运行脚本时会出现大量的随机空块。

所以,我被困住了。我不禁觉得有一个很好的数学解决方案,使用固定数量的变量,但我看不到它。如果不这样做,有没有人知道另一种方法来实现我正在寻找的东西?

2 个答案:

答案 0 :(得分:1)

  • 无需将所有信息保存到数据库中。对于每个矩形,您只需要顶部/左侧坐标+宽度/高度。

  • 那么你应该能够通过一个查询获得给定坐标的最大可用空间(例如,得到最小x,它比你的-x大,并且也在所需的y空间内)

<强>更新

对于max-width,您可以使用:

SELECT   `x` - :x AS `maxWidth`
FROM      `test`
WHERE     `x` > :x
AND       (`y` > :y OR `y` + `h` > :y)
ORDER BY  `y`, `y` + `h`
LIMIT     1

和max-height:

SELECT   `y` - :y AS `maxHeight`
FROM      `test`
WHERE     `y` > :y
AND       (`x` > :x OR `x` + `w` > :x)
ORDER BY  `x`, `x` + `w`
LIMIT     1

答案 1 :(得分:1)

读完一遍,也许会有所帮助。我没有对它进行测试,但我已经评论了我的意图,所以你应该能够提出基于它的东西。     

//create some globals we will need
$region_id = 1;
$current_x = 0;
$current_y = 0;
    $squares = array();

//Create the base grid
$grid = array(GRID_WIDTH);
foreach($grid as $a)
{
    $a = array(GRID_HEIGHT);
    $a = array_fill(0, count($a), 0);
}
//$grid[0][0] will be the top left square



//Iterates over the grid until it is full
while($current_x != (-1) && $current_y != (-1))
{
    //We just need to set these counters back to their minimums
    $max_x = $current_x;
    $max_y = $current_y;

    //Lets see how many spaces we have between current x and end of the row
    //$max_x will be the maxiumum newX2
    for($x = $current_x; $x<GRID_WIDTH; $x++)
    {
        if($grid[$x][$current_y]==0)
        {
            $max_x = $x;
        }
    }

    //Lets create a width between 1 and the max left in the row
    $newX1 = $current_x;
    $newX2 = rand($current_x, $max_x)

    //Now lets see how tall we can make it by going down the y until we hit a square or the end.. do for each x
    for($x = $newX1; $x<newX2;$x++)
    {
        for($y = $current_y; $y<GRID_HEIGHT; $y++)
        {
            if($grid[$x][$y]==0)
            {
                //We just need the maxiumum y we can have based on our already determined width
                //Since this distance has to be smallest possible distance
                //We only let max_y get larger on the first iteration of x
                if($y>$max_y && $x==$newX1)
                {
                    $max_y = $y;
                }
            }
        }
    }

    //lets create a height bettwen 1 and the max
    $newY1 = $current_y;
    $newY2 = rand($current_y, $max_y);

    //create a spacewith these values
    occupySpace($newX1, $newX2, $newY1, $newY2, $grid, $region_id);
            $squares[] = array($newX1, $newX2, $newY1, $newY2);

    //Iterate over the grid looking for an empty space
    //First lets set current_x and current_y to -1.  We will use this to evalute done
    $current_x = -1;
    $current_y = -1;
    for($x = 0; $x<GRID_WIDTH; $x++)
    {
        for($y = 0; $y<GRID_HEIGHT; $y++)
        {
            //Looking for any space that hasn't been occupied, if one is found break both for loops
            if($grid[$x][$y]==0)
            {
                $current_x = $x;
                $current_y = $y;
                break 2;
            }
        }
    }

}

//fills all spaces in the region with the current region id and increments region id
function occupySpace($x1, $x2, $y1, $y2, &$grid, &$region_id)
{
    for($x=$x1; $x<$x2; $x++)
    {
        for($y=$y1; $y<$y2; $y++)
        {
            $grid[$x][$y] = $region_id;
        }
    }
    $region_id += 1;
}
?>

更新:此解决方案最初并未跟踪已创建的“区域”。现在它们存在于数组$ square中。

PS - 如果这将成为您的脚本/业务的重要部分,我会考虑为Grid和region编写一些类,