寻找一种好的世界地图生成算法


97

我正在开发类似《文明》的游戏,并且正在寻找一种生成类似地球的世界地图的良好算法。我已经尝试了一些替代方法,但是还没有找到真正的赢家。

一种选择是使用Perlin噪声生成高度图,并添加一定水平的水,以使世界上约30%的土地为土地。虽然Perlin噪声(或类似的基于分形的技术)经常用于地形并且相当真实,但它并不能提供很多控制所得大陆的数量,大小和位置的方式,我想从游戏角度来看。

佩林噪音

第二种选择是从随机放置的单块种子开始(我正在研究一个瓷砖网格),确定该大陆所需的尺寸,然后每转一圈添加一个与现有大陆水平或垂直相邻的瓷砖,直到您已达到所需的大小。重复其他大洲。该技术是《文明4》中使用的算法的一部分。问题在于,放置前几个大洲之后,有可能会选择一个被其他大洲包围的起始位置,因此不适合新的大洲。而且,它倾向于使各大陆之间的距离太近,导致某些东西看起来比大洲更像一条河流。

随机扩展

有没有人碰巧知道一个好的算法,可以在基于网格的地图上生成现实的大洲,同时又能控制其数量和相对大小?


2
我不知道为什么要解决90个以上投票的自然问题。投票重新开放。
约翰·科尔曼

Answers:


38

您可以从自然中汲取灵感,并修改第二个想法。生成大洲(大小都相同)后,让它们随机移动,旋转,碰撞和变形,以及彼此漂移。(注意:这可能不是最容易实现的方法。)

编辑:这是完成此操作的另一种方法,即实现— 游戏的多边形地图生成


2
这是一个好主意。我不知道如何直接模拟构造板块,但只要每个大洲都“拥有”自己的地砖(而不是简单地充当地图阵列的生成器),并且基本上位于其上或充当其板块,实施起来并不难。我现在必须尝试一下:)
nathanchere

@FerretallicA谢谢。我很想亲自尝试一下-当我有更多空闲时间时... :-)
David Johnstone 2010年

3
您始终可以使用的一种便宜的技巧是在数学函数中定义定义“良好”映射的内容,然后创建十个随机的次要更改,然后使用其中的最佳值。继续这样做,它将朝着您想要的地图的方向漂移。
dascandy 2011年

您可以对K-means聚类进行修改,以确定每块土地归哪个“大陆”所有。然后使用Voronoi图(一旦定义了簇,这应该很容易)来确定板块边界...对于Voronoi中的每个线段,您将确定一个随机运动矢量,并且应该能够确定地震带与火山带然后,每个陆地点都将基于其相对于板块边界的位置而最终得到一个单独的矢量,并且应该最终得到一个相当真实的模拟来进行工作。
史蒂夫·

我正在使用单块种子方法。关于如何添加更复杂的地形(例如山脉)的任何建议?
Tyshka '16

11

我建议你备份一下

  1. 想想是什么使“好”的大陆。
  2. 编写一种算法,可以分辨出一个好的大陆布局。
  3. 优化算法,以便您可以量化良好布局的质量。

一旦有了适当的位置,就可以开始实施应如下所示的算法:

  • 产生cr脚的大陆,然后加以改善。

为了进行改进,您可以尝试各种标准的优化技巧,无论是模拟退火,遗传编程还是完全临时的东西,例如将随机选择的边角正方形从大陆上的任意位置移动到与质心相反的边缘。但是关键是要能够编写一个程序,该程序可以区分好大陆和坏大陆。从手绘大洲以及测试大洲入手,直到获得自己喜欢的东西。


1
在这种情况下,这毫无意义。就像是说,对于分形生成器,您应该编写一个程序来生成cr脚的分形,然后尝试编写一个程序来告诉您所拥有的是否是一个好的分形。从一开始就将其“正确”变得容易得多。否则,您将完全偏离问题的重点和范围。
nathanchere 2010年

1
@FerretallicA非常不同意。有了图形,从屏幕上得到的东西开始非常有用。然后您的右脑可以开始做一些工作。
luser droog

11

我写了一些类似的内容,作为您自动仿制《文明1》的屏幕保护程序样式的内容。为了记录,我在VB.net中写了此内容,但由于您在问题中没有提及任何语言或平台,因此我会继续它抽象。

“地图”指定了大洲的数量,大洲的大小方差(例如,1.0将使所有大洲具有相同的近似陆地面积,减小到0.1将允许大洲以最大大陆质量的1/10的形式存在),最大陆地面积(以百分比表示)产生,以及中央土地偏向。对于每个大陆,“种子”在地图上随机分布,并根据中心偏差在地图中心加权(例如,较低的偏差会产生与地球更相似的分布大陆,而较高的中心偏差会更像地球Pangaea)。然后,对于每次增长迭代,“种子”都会根据分配算法分配地砖(稍后会详细介绍),直到达到最大土地面积为止。

土地分配算法可以达到您想要的精确度,但我发现使用各种遗传算法并掷骰子可获得更有趣的结果。康威的《人生游戏》是一个非常容易上手的游戏。您需要添加一些具有全局意识的逻辑,以避免像大洲这样的事情相互扩散,但是在大多数情况下,事情要自理。我发现,使用更多基于分形的方法(这是我的第一个倾向)的问题是结果要么看起来过于图案化,要么导致了太多需要骇人听闻的变通办法的场景,以至于仍然无法获得足够动态的结果。根据您使用的算法,您可能需要对结果应用“模糊”传递,以消除诸如丰富的单方海洋瓦片和方格的海岸线之类的东西。如果发生了像被其他几只动物包围而又无处生长的大洲之类的事情,请将种子移到地图上的新点,然后继续进行生长。是的,这可能意味着您有时会获得比计划中更多的大洲,但是,如果您确实确实不希望这样做,那么另一种避免出现这种情况的方法是使增长算法产生偏差,从而使他们倾向于朝着与其他区域的距离最小的方向进行增长种子。最坏的情况下(无论如何,我认为)可以在种子无处可生长并生成新地图时将系列标记为无效。只需确保设置了最大尝试次数即可,因此,如果指定了任何不切实际的内容(例如在10x10的木板上拟合50个加权均匀的大洲),它都不会永远花费在寻找有效的解决方案上。

我不能保证Civ等是如何做到的,当然也不能涵盖气候,土地使用年限等问题,但是通过使用种子生长算法,您可以获得非常有趣的类似于大洲,群岛等的结果。您可以也使用相同的方法生产看起来像“有机”的河流,山脉等。


11

我用JavaScript创建了与您的第一张图片相似的图片。它不是非常复杂,但是可以工作:

http://jsfiddle.net/AyexeM/zMZ9y/

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<style type="text/css">
    #stage{
        font-family: Courier New, monospace;
    }
    span{
        display: none;
    }
    .tile{
        float:left;
        height:10px;
        width:10px;
    }
    .water{
        background-color: #55F;
    }
    .earth{
        background-color: #273;
    }
</style>
</head>

<body>


<div id="stage">

</div>

<script type="text/javascript">

var tileArray = new Array();
var probabilityModifier = 0;
var mapWidth=135;
var mapheight=65;
var tileSize=10;

var landMassAmount=2; // scale of 1 to 5
var landMassSize=3; // scale of 1 to 5


$('#stage').css('width',(mapWidth*tileSize)+'px');


for (var i = 0; i < mapWidth*mapheight; i++) {

    var probability = 0;
    var probabilityModifier = 0;

    if (i<(mapWidth*2)||i%mapWidth<2||i%mapWidth>(mapWidth-3)||i>(mapWidth*mapheight)-((mapWidth*2)+1)){

        // make the edges of the map water
        probability=0;
    }
    else {

        probability = 15 + landMassAmount;

        if (i>(mapWidth*2)+2){

            // Conform the tile upwards and to the left to its surroundings 
            var conformity =
                (tileArray[i-mapWidth-1]==(tileArray[i-(mapWidth*2)-1]))+
                (tileArray[i-mapWidth-1]==(tileArray[i-mapWidth]))+
                (tileArray[i-mapWidth-1]==(tileArray[i-1]))+
                (tileArray[i-mapWidth-1]==(tileArray[i-mapWidth-2]));

            if (conformity<2)
            {
                tileArray[i-mapWidth-1]=!tileArray[i-mapWidth-1];
            }
        }

        // get the probability of what type of tile this would be based on its surroundings 
        probabilityModifier = (tileArray[i-1]+tileArray[i-mapWidth]+tileArray[i-mapWidth+1])*(19+(landMassSize*1.4));
    }

    rndm=(Math.random()*101);
    tileArray[i]=(rndm<(probability+probabilityModifier));

}

for (var i = 0; i < tileArray.length; i++) {
    if (tileArray[i]){
        $('#stage').append('<div class="tile earth '+i+'"> </div>');
    }
    else{
        $('#stage').append('<div class="tile water '+i+'"> </div>');
    }
}

</script>

</body>
</html>

3
我喜欢非常优雅的实现。
nathanchere

谢了,兄弟们 !!非常轻巧
Liberateur

9

多边形地图生成文章介绍了不使用Voronoi多边形的逐步地图生成。

这个家伙还提供所有源代码。它是Flash(ActionScript 3 / ECMAScript),但可以转换为任何其他面向对象的语言

或者尝试使用在某些分形环境软件(例如TerraJ)中实现的算法


5

只是在这里想一想:

选择一些起点,并为每个起点分配一个随机绘制的(希望的)尺寸。如果需要,可以为计划的大陆和计划的岛屿维护单独的尺寸绘制。

循环遍历土地元素,在尚未达到计划大小的地方加一平方。但是有趣的部分是权衡每个相邻元素将成为一个元素的机会。一些可能导致以下问题的建议:

  1. 到最近的“其他”土地的距离。更好的是产生广阔的海洋空间。越近越好,使渠道狭窄。您必须决定是否还要让位合并。
  2. 与种子的距离。越近越好,意味着土地块很紧凑,越远越好,意味着长了一点
  3. 相邻的现有土地广场的数量。支持许多相邻正方形的权重可以使您平滑滑行,而不支持少数则可以使您有很多入口和半岛。
  4. 附近是否存在“资源”广场?取决于游戏规则,何时生成资源方块以及是否要使其变得容易。
  5. 您会允许钻头靠近两极吗?
  6. ??? 不知道还有什么

继续进行下去,直到所有土地都达到规划的大小或由于某种原因而不再增长。

请注意,将参数设置为这些加权因子可以使您调整生成的世界的类型,这是我对某些Civ所喜欢的功能。

这样,您将需要在每个位上分别进行地形生成。


4

您可以尝试使用菱形平方算法或佩林噪声生成类似高度图的图像。然后,将范围值分配给地图上显示的内容。如果您的“身高”从0到100,那么请制作0-20水,20-30海滩,30-80草,80-100山。我认为notch在微型飞机中做了类似的事情,但是我不是专家,在终于使它工作之后,我只是处于菱形方形的心态。


3

我认为您可以在此处使用“动态编程”风格的方法。

首先解决小问题,然后巧妙地组合解决方案以解决更大的问题。

A1= [elliptical rectangular random ... ]// list of continents with area A1 approx. 
A2= [elliptical rectangular random ... ]// list of continents with area A2 approx.
A3= [elliptical rectangular random ... ]// list of continents with area A3 approx.
...
An= [elliptical rectangular random ... ]// list of continents with area An approx.

// note that elliptical is approximately elliptical in shape and same for the other shapes.

Choose one/more randomly from each of the lists (An).

Now you have control over number and area of continents.

You can use genetic algorithm for positioning them 
as you see "fit" ;)

看看一些“图形布局算法”会非常好

您可以修改它们以适合您的目的。


3

我有一个类似于构造板块答案的地图创建想法。它是这样的:

  1. 如果rnd <= 0.292(地球上陆地干燥的实际百分比),则扫过网格正方形,为每个正方形提供一个“陆地”正方形。
  2. 将每个土地块向其最近的较大邻居迁移一个正方形。如果邻居是等距的,则朝着更大的块。如果块大小相等,则随机选择一个。
  3. 如果两个陆地广场相互接触,请将它们分组为一个大块,从现在开始将所有广场移动为一个。
  4. 从步骤2重复。在连接所有块后停止。

这类似于重力在3D空间中的工作方式。这很复杂。满足您需求的简单算法如下:

  1. 在随机的x,y位置和彼此可接受的距离处放入n个启动器土地广场。这些是您各大洲的种子。(使用勾股定理,确保种子与其他种子之间的距离最小。)
  2. 如果该方向是海洋广场,则从现有土地广场随机产生一个土地广场。
  3. 重复第2步。当陆地正方形占地图总大小的30%时,停止。
  4. 如果各洲之间的距离足够近,则可以根据需要放下陆桥以模拟巴拿马型效果。
  5. 根据需要放入较小的随机岛,以获得更自然的外观。
  6. 对于您添加的每个额外的“岛屿”广场,使用相反的相同算法从大陆上切出内陆海洋和湖泊广场。这将使土地百分比保持在所需的数量。

让我知道如何解决。我从来没有尝试过。

PS。我看到这与您尝试过的类似。除了它在开始之前立即设置所有种子外,因此各洲之间的距离将足够远,并且在地图填满后将停止。


2

我实际上没有尝试过,但是它受到了大卫·约翰斯通(David Johnstone)关于构造板块的回答的启发。我尝试在自己的旧Civ项目中自己实现它,当涉及到处理碰撞时,我有了另一个想法。每个大陆不是直接生成图块,而是由节点组成。将质量分布到每个节点,然后使用二维元球方法生成一系列“斑点”大陆。仅仅通过移动节点,构造和大陆漂移就很容易“伪造”。根据您要进行的复杂程度,您甚至可以应用诸如电流之类的方法来处理节点移动并生成与板块边界重叠相对应的山脉。可能不会在游戏玩法方面增加太多,

如果您以前没有使用过metaball,可以很好地解释它们:

http://www.gamedev.net/page/resources/_//feature/fprogramming/exploring-metaballs-and-isosurfaces-in-2d-r2556


2

这就是我的想法,因为我将要实现我在开发中的游戏所具有的类似功能。:

世界分为区域。取决于世界的大小,它将确定多少个区域。对于此示例,我们假设一个中等大小的世界,有6个区域。每个网格区域分为9个网格区域。这些网格区域每个分成9个网格。(这不是用于角色移动,而只是用于创建地图)。网格用于生物群落,网格区域用于拱形土地特征(大陆与海洋),而区域用于整体气候。网格分解为瓷砖。

随机生成的区域将获得分配的逻辑气候集。例如,将网格区域随机分配给它;海洋或陆地。网格根据其网格区域和气候,随机分配有修饰符的生物群系,这些是森林,沙漠,平原,冰川,沼泽或火山。一旦分配了所有这些基础知识,就可以使用填充瓷砖集的基于随机百分比的函数将它们融合在一起。例如; 如果您有一个森林生物群落,而一个沙漠生物群落旁边,则有一种算法可以降低瓷砖“森林化”的可能性并增加其“荒芜”的可能性。因此,大约在它们之间的一半处,您会看到一种混合的影响,将两个生物群落结合在一起,从而在它们之间实现了某种程度的平滑过渡。从一个网格区域过渡到下一个网格区域可能需要花费更多的工作来确保逻辑陆地的形成,例如,一个网格区域的生物群落与另一网格区域的生物群落相接触,而不是根据接近程度简单地切换百分比。例如,从生物群系的中心到生物群落的边缘有50个图块,这意味着从其接触的边缘到下一个生物群落的中心有50个图块。从逻辑上讲,从一个生物群落到另一个生物群落将有100%的变化。因此,随着瓦片越来越靠近两个生物群落的边界,该百分比缩小到大约60%左右。我认为,过大的可能性越过边界越过生物群系是不明智的,但是您会希望边界有所融合。对于网格区域,百分比变化将更加明显。百分比不会下降到60%左右,而只会下降到80%左右。然后必须进行第二次检查,以确保在靠近海洋的陆地生物群系中间没有随机的水瓦片。因此,要么将那个水砖连接到海体上,以形成一个解释水砖的通道,要么将其全部移除。水基生物群落中的土地使用岩石露头等更容易解释。

哦,有点傻,对不起。


嘿!我正在做一些研究,因为我试图生成一个地图。只是出于好奇,结果如何?
VivienLeger

1

我将根据一些您知道“有效”的布局(例如2x2网格,菱形等,有些抖动)来放置分形地形,但高斯分布的阻尼峰会向下延伸至大陆中心的边缘。将水位降低,以便大部分土地降到您靠近边缘为止。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.