如何生成城市街道网络?


16

我想为游戏创建一个城市生成器,但是在生成的一开始我就面临一个问题:道路系统。

由于这是一个中世纪世界,所以我不希望像许多现代城市一样制定网格计划。理想情况下,我更喜欢伪随机生成的大型大道和较小街道,在这些地方可能会迷路,但仍需遵循一些逻辑-而不是完全迷宫。
看起来像是自然生长的城镇。

为了简单起见,假设我的城市处于平坦且稳定的地形上,没有任何过河或救济问题。之后,我可以尝试将其集成到解决方案中。

我没有确定我的城市的确切大小或位置,因此,如果您有一个仅适用于具有精确形式(正方形,圆形,矩形等)的城市的解决方案,我会采用。


2
您可能想看看Introversion Software为Subversion制作的程序城市生成器。虽然游戏本身被取消了,但是它们的生成器周围有很多镜头。
菲利普

您是否有想要的示例(目标时间段内的现实示例,其他游戏,草图等的示例)?在“不是网格”和“不是完整的迷宫”之间有很多选择。
皮卡列克

@Pikalek我没有提供更多精度,因为我没有。我不是在寻找非常具体的东西,任何不生成迷宫或网格计划的生成示例都无法满足我的需求。
阿修索

Answers:


21

Parish和Müller的《城市程序化建模》是从程序化城市生成开始的一个好地方。他们的论文提出了一个L系统,其中将有关人口密度和道路模式(矩形网格,径向和最小海拔变化)的规则进行组合,然后进行固定以适应诸如水滨和道路美观之类的局部约束。尽管该系统的结果令人印象深刻,但已被批评为不必要地复杂。Barrett的替代解决方案在Rudzicz的Spare Parts开发博客中进行了重新阐述,如下所示:

  • 维护“拟议”道路清单
  • 按顺序评估他们
  • 是否可以接受(经过或不经过一些小的修改)
  • 存储每条接受的道路,同时“提议”一些更多的分支

这种方法消除了Parish和Müller的L系统中继承的大多数符号重写内务处理方法。您可以在此处查看此方法演示

这种方法的优点是它与城市形状无关-您可以根据需要添加轮廓约束,因此可以根据游戏设计的需求而不是算法来确定城市的形状。根据您的城市规模,这可能就足够了。这是上面的演示的结果,细分上限为100 在此处输入图片说明 。以下是细分限制为500的结果: 在此处输入图片说明

您可以部分地通过更改道路分支规则,避免90度角等来对此进行调整。如果布局仍然过于规则,这是我的更正:

将您的城市网格转换成一个图形,其中每条街道是一条边,每个路口是一个节点。接下来,使用您喜欢的任何算法将图形转换为迷宫。这是变成迷宫的最后一个例子: 在此处输入图片说明

现在输出有相反的问题,就像迷宫一样。但是现在我们可以应用Jamis Buck的Dungeon Generator的Secret Workings中的两种技术。首先,通过删除一些死胡同的走廊来增加稀疏性。接下来,通过添加创建循环的道路(即在图形中引入循环)来增加连接性。这是一个示例结果: 在此处输入图片说明

注意:通过仅对城市网格应用边缘去除,可以从面向网格的早期布局阶段(在生成迷宫之前)直接获得相同的最终结果。这种方法的问题在于,您必须确保移除边缘不会对城市造成划分,从而使部分区域无法触及。


6

如果您在Google上查找中世纪/旧城市规划,您会发现许多不同的变化,主要是基于城市起源(例如,随机定居点与有组织的军事阵地)。

我认为您正在寻找一种更加自然生长/混乱的解决方案。

对于这些,我会尝试这样的方法:

  • 从一条从一端到另一端的主干路开始(并理想地连接其他定居点。如果需要,创建第三条道路,以便获得一个可开始定居点的路口。
  • 在道路上放置一些房屋(仅在一侧)。
  • 现在沿着房屋加宽那条路,并在另一侧添加一个主要地标(通常是教堂,但这也可能是一些磨坊或类似的)。这将是您的中心/市场。
  • 现在在带有房屋的区域外选择两个位置,并创建一条封闭房屋的新道路。
  • (可选)在连接新旧道路的房屋之间创建一些较小的盟友。
  • 现在重复直到对“核心”感到满意为止:
    • 再添加一些房子。
    • 添加另一条封闭它们的道路。
    • 加上连接道路的小巷。
  • 一旦对此感到满意,就可以完成。如果应该是城镇,则将其用墙围起来,并重复几次最后的步骤,在墙外增加其他房屋。

3

首先,有很多方法可以进行程序生成,但都不是一件容易的事,我将通过某种方式来决定如何使其能够工作,取决于您采用,修改或丢弃它。

JS中的伪代码,因为它更易于理解。

1º定义了一个入口点,当您要构建一个中世纪城市时,我们将从一个正方形开始,因此可以说您的城镇将有300个正方形单位,并且正方形将在其中间(用X表示)。

       300
________________
|               |
|               |
|               | 300
|       X       |
|               |
|               |
|_______________|

const square = [ 150, 150 ];

2º现在我们将成为大道,它们的数量将是随机的,它们将是笔直的,并且将从中间广场或其他大道开始

let avenues = [] // will contain start and end [[sx,sy],[ex,ey]]
const n_avenues = RANDOM(4, 8); // number of avenues
const n_av_from_square = RANDOM(0, avenues); // starting in the square

for av in av_from_square
  avenues.push(square, [RANDOM(0, 200) + 100, RANDOM(0, 200) + 100])
  // we want avenues to have, at least 100 units length, thats why we randomize just te last 200 units of the whole town size

这应该给您一个广场和几条主要街道

       300
________________
|   \\          |
|    \\         |
|     \\        | 300
|       X=====  |
|               |
|               |
|_______________|

现在我们必须设置不在主广场开始的道路,它们将与其他道路相交

for av in (n_avenues - av_from_square){
  const av_to_intersect = avenues[RANDOM(0,avenues.length)];

  //check av_to... and get a perpendicular vector (explained bellow)
  av[0] = [ av_to_intersect[0][1], - av_to_intersect[0][0] ];
  av[1] = [ av_to_intersect[1][1], - av_to_intersect[1][0] ];

}

要获得垂直向量,您必须交换x,y线并取反新的y:

刷== x:noswiped.y,y:-1 *(noswiped.x)

现在您应该有类似的东西,它看起来不像一个城镇吗?:P

       300
________________
|   \\  //      |
|    \\//  ||   |
|     \\   ||   | 300
|    //\X=====  |
|   //     ||   |
|          ||   |
|_______________|

3º现在,您只需要将大街与短街道互连即可,也可以在整个城镇中生成随机的正方形,并对其进行相同的制作,或者仅从第二个正方形生成小街道,这取决于您。

请记住,您的街道最短,小镇看上去很混乱。

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.