我目前正在制作一款专注于程序生成内容的应用。到目前为止,我已经使用单纯形噪声成功实现了地形和地图形状的程序生成。我对它的外观感到非常满意。现在,我正在尝试为城市做同样的事情。我只需要生成街道和建筑物的2D布局即可。我研究了它,似乎大多数人都建议使用L系统。但是我似乎无法将他们的头缠住。我得到了概念,但没有将实现转化为代码。是否有人提供用于程序生成城市的L系统的代码示例,或有关处理城市的其他方法的建议?
我目前正在制作一款专注于程序生成内容的应用。到目前为止,我已经使用单纯形噪声成功实现了地形和地图形状的程序生成。我对它的外观感到非常满意。现在,我正在尝试为城市做同样的事情。我只需要生成街道和建筑物的2D布局即可。我研究了它,似乎大多数人都建议使用L系统。但是我似乎无法将他们的头缠住。我得到了概念,但没有将实现转化为代码。是否有人提供用于程序生成城市的L系统的代码示例,或有关处理城市的其他方法的建议?
Answers:
据我所知*,L系统是一组类似语法的替换规则,您可以递归应用这些规则以获得有趣的“有机”结果。
植物是经常使用L系统的地方,因为它们表现出大量的递归生长(即分支分裂成更多的分支)。举一个简单的例子,我将展示一个使用L系统生成的“棒棒糖”树:
variables : | o (these are the things that will grow)
start : o
| (this is what we start with)
rules : (o → o o) (these are the substitution rules that we apply
\ / one step at a time)
因此,在第一代,我们才刚刚开始:
o
|
在第2代中,我们遵循每个规则,并根据规则替换现有部分。我们将“球”替换为“两棍和球”:
o o
\ /
|
第三代:
o o o o
\| |/
\ /
|
很快,我们将有一棵漂亮的(cr脚的)大树!
要在代码中执行此操作,您可以递归执行此操作(即DFS),将规则连续应用于相同的部分,直到达到任意端为止,也可以像本例中那样反复执行(即BFS) ,对所有元素执行一条规则“通过”并重复许多步骤。那是:
递归地:
tree = start
grow(tree, start)
func grow(tree, part)
if this part of the tree is big enough
stop
if part is 'o'
replace part with 'o\/o'
grow(tree, the left 'o')
grow(tree, the right 'o')
反复:
tree = start
for a number of iterations
for each part in tree
if part is 'o':
replace with 'o\/o'
L-Systems的许多用途都通过细分来执行“增长”步骤-也就是说,随着“增长”,零件不断变小,而更大的零件就被分割了。否则,您正在成长的系统可能会开始在自身之上重叠。您会在我的棒棒糖树示例中看到,我神奇地通过更改新分支的形状来确保两个分支不会在中间重叠。让我们使用细分来制作城市示例:
variables: block_vertical block_horizontal road_vertical road_horizontal
start: block_vertical
rules: (block_vertical → block_horizontal road_vertical block_horizontal)
(block_horizontal → block_vertical road_horizontal block_vertical)
一分钟之内,这将是有意义的。
第1代:
+--------------------+
| |
| |
| |
| V |
| |
| |
| |
+--------------------+
单个无聊的垂直块。(V代表垂直。)
第2代:我们将垂直路段替换为水平路段,中间使用一条垂直路
+--------------------+
| r |
| r |
| r |
| H r H |
| r |
| r |
| r |
+--------------------+
r代表路!我已经随机分配了分割,我们不想在PCG中浪费常规零件。
第3代:我们用水平路段分开的垂直路段替换水平路段。保留现有道路;他们没有任何规则。
+--------------------+
| V r |
| r |
|rrrrrrrr |
| r V |
| V r |
| rrrrrrrrrrrrr|
| r V |
+--------------------+
注意道路之间如何相互连接,这很好。重复此次数足够多,您将得到如下结果(公然撕掉一个相关的答案):
请注意,我没有涉及很多细节,并且看起来“明显”生成了此结果-实际城市看起来有些不同。这就是使PCG有趣/困难的原因。您可以做很多事情来调整和改善结果,但是与L-Systems无关,我将在这里留下答案。希望这可以帮助您入门。
*-尽管我遇到过特定类型的语法和PCG植被,但我尚未正式学习L系统。如果我对任何定义或概念有误,请纠正我
@congusbongus的回答非常好,让我补充一些内容。
街区需要根据与街区接壤的所有道路划分为多个建筑区域。当您到处都是路时,总体格局是一圈。例如,请参见以下链接:http : //oldurbanist.blogspot.fr/2012/01/city-blocks-spaces-in-between.html
(取决于密度,环中心可能没有空间,请参见九龙)。
一旦完成了块,就需要生成建筑物。他们有点棘手,需要两次通过。它们是部分相互依赖的:生成器不应在下一个建筑物侧壁的前面创建窗口。
为了增加生命,您可能希望通过地形或经济地图等环境来影响这一代:道路(旧金山除外)倾向于绕过大山丘,而不是直行,并且房屋类型繁多受他们所在城市部分的影响。
玩得开心。