Layer-Based Procedural Generation for Infinite Worlds
Summary
TLDR本文介绍了一种无边界无限世界的程序生成方法。通过使用滚动窗口和2D数组,可以创建一个在任何方向上无限延伸的世界。作者探讨了在无限世界中进行程序生成时需要考虑的问题,如如何在不同层级上加载和调整点的位置,以及如何计算世界之间的连接。这种方法允许即使在没有边界的情况下,也能实现复杂度较高的程序生成。
Takeaways
- 🌐 无限世界可以通过滚动窗口的方式在2D数组上实现。
- 🔄 世界可以无限扩展,通过在不同层级加载细节来实现。
- 🔍 在无限世界中,无法一次性获取所有邻居信息,因为总会有新的邻居出现。
- 📊 通过分层生成,可以在不知道整个画面的情况下进行复杂的程序生成。
- 🔢 每一层的生成依赖于前一层的信息,确保相邻单元格的数据一致性。
- 🔄 层与层之间需要加载相邻单元格的信息,以便调整和优化生成的点。
- 🌐 通过三角剖分和选择性连接,可以创建自然且不完全连接的世界。
- 🔄 随着层数的增加,对周围环境的信息了解越多,但最远路径只能在低抽象层级加载。
- 🔄 游戏开发中,除了上述方法,还可以使用完全解耦的层,它们可以有不同的网格分辨率。
- 🔄 加载新层时,旧层会升级或卸载,形成一个动态的加载和卸载过程。
- 🔄 这种方法允许在没有边界的情况下进行高复杂度的程序生成。
Q & A
什么是无限世界中的程序生成?
-无限世界中的程序生成是一种技术,它允许创建一个理论上无限大的游戏世界,通过滚动窗口的方式来探索,这个窗口随着玩家的移动而移动。
在程序生成中,如何处理无限世界中的边界问题?
-在无限世界中,没有明确的边界,因此需要一种方法来动态加载和卸载世界的不同部分。这通常涉及到在玩家接近当前加载区域的边缘时,加载新的区域,并在玩家远离时卸载旧的区域。
如何确保在无限世界中生成的点分布均匀?
-为了确保点分布均匀,需要在生成随机点后进行调整。这包括了解邻近单元格中的点,以避免点过于接近。通过这种方式,可以确保点在整个无限世界中分布得相对均匀。
在程序生成的无限世界中,如何确定世界的大小?
-在无限世界中,世界的大小不是固定的,而是根据玩家的位置和视野动态确定的。世界的大小取决于玩家当前加载区域的层级,以及这个区域与邻近区域的连接情况。
什么是程序生成中的层级结构?
-程序生成中的层级结构是一种组织和处理数据的方法,其中每个层级依赖于更低层级的数据。例如,一个层级可能需要知道邻近所有八个单元格的数据才能进行计算,这样可以确保生成的数据是连贯的。
在无限世界中,如何实现不同世界之间的连接?
-为了实现不同世界之间的连接,首先进行点的三角剖分,然后选择一个子集来形成连接。这样可以确保世界之间有路径可以相互到达,但不是每个世界都直接相连,有时可能需要通过第三个世界来实现转移。
在程序生成中,如何处理不同层级之间的数据依赖?
-在程序生成中,每个层级的数据依赖于更低层级的数据。这意味着在进行高层级的数据计算之前,必须先加载并处理所有依赖的低层级数据。这种依赖关系决定了加载区域需要扩展的范围。
在无限世界中,如何实现动态的加载和卸载?
-动态加载和卸载是通过在玩家移动时加载新的层级和卸载旧的层级来实现的。随着玩家的移动,最外层的单元格被加载到新的层级,而已经加载的单元格则升级到更高的层级。当单元格移出视野范围时,它们会被逐步卸载。
在程序生成的无限世界中,如何处理不同层级的分辨率?
-在某些情况下,可以使用完全解耦的层级,这些层级可以有不同的网格分辨率。每一层都可以独立地请求信息,而不需要关心其他层的内部实现细节,这样可以处理不同分辨率的数据。
在无限世界中,如何确保邻近单元格之间的连接?
-为了确保邻近单元格之间的连接,可以在每个邻近单元格中选择一个世界,使其与当前单元格中的某个世界相连。这样可以确保玩家可以从任何世界到达其他世界,尽管可能需要通过一个中间世界。
Outlines
🌐 无限世界的程序生成
介绍了如何通过滚动窗口的方式实现一个无限世界的程序生成。通过2D数组来模拟无限世界,并且讨论了在没有边界的情况下进行程序生成时需要考虑的问题。提出了一种抽象的环形世界概念,并通过不同层次的细节加载来展示如何在无限世界中实现局部的细节展示。
🔍 程序生成的实现细节
详细讨论了在无限世界中进行程序生成时的实现细节。包括如何调整随机生成的点以避免过于集中,以及如何计算世界之间的连接。介绍了一种分层的方法,每一层都需要加载相邻层的信息,以确保生成的点和连接是合理的。还提到了如何通过三角剖分来确定连接点,以及如何确保每个相邻的单元格之间至少有一个连接。
🔄 层次加载与卸载
描述了在游戏开发中如何实现层次的加载和卸载。随着玩家的移动,新的层次被加载,而已经加载的层次会根据其在层次结构中的位置进行升级或降级。当单元格移出视野时,它们会被卸载到更低的层次,直到完全卸载。这种方法允许无限世界的程序生成,同时保持了对周围环境的有限了解。
Mindmap
Keywords
💡程序生成
💡无限世界
💡2D数组
💡滚动窗口
💡层级生成
💡随机点
💡调整点
💡连接点
💡细节层次
💡加载与卸载
Highlights
介绍了如何通过滚动窗口实现无限世界的程序生成。
讨论了无限世界程序生成时不需要边界的考虑因素。
提出了一种抽象的环形世界概念,通过路径连接各个部分。
解释了在无限世界中,由于缺乏完整画面,无法获取所有邻居信息的问题。
描述了一种分层的程序生成方法,每层可以包含更多信息。
说明了最外层单元格在零层时创建随机点列表的方法。
讨论了如何调整随机点以避免过于集中的问题。
解释了第一层如何调整点,以及为何需要加载邻近单元格的信息。
介绍了第二层如何计算世界的半径,并确保使用调整后的点。
讨论了如何通过三角化和选择子集来确定点之间的连接。
说明了如何确保每个邻近单元格至少有一个世界与当前单元格相连。
描述了随着层数增加,对周围环境信息的了解也会增加。
提到了在更高层次上计算星球内部信息的方法。
介绍了一种不同层次完全解耦的方法,具有不同的网格分辨率。
讨论了加载新层时的动态窗口和卸载过程。
强调了这种方法允许无限世界的程序生成,尽管没有边界。
Transcripts
I'm going to talk a bit more about how
to do procedural generation for an
infinite world back in May I wrote a
blog post called rolling grids for
infinite worlds that talk about how you
can have an infinite world with
procedural generation where you
basically have a 2d array that you can
treat as infinite by having a scrolling
a rolling window into your world that
Scrolls together with whether characters
and I'm going to go a bit into some of
the considerations here that you'll have
to consider when doing procedural
generation that basically doesn't have
any boundaries so what we're looking at
here is some kind of circle worlds
they're bit abstract at this stage put
them in to represent a kind of worlds
that are connected by some pathways that
you can use to travel between them and
this world is extends infinitely in all
directions so I could I can scroll this
world here and it basically goes on
forever in any direction and there's
many things like this we can do all
kinds of interesting things with
procedural generation which are not that
triggered by themselves for something
like this if it had bounds you could
throw in a bunch of random points and
give them some radiuses and make sure
they don't overlap adjust as necessary
and then find some good way to connect
them and once you've handled all that
for all the points then you're done but
the problem is when
it's infinite then you never have the
whole picture so you never have all the
neighbors available because they'll
always be some extra neighbors outside
of the currently loaded bounds so let's
try to look at how this is implemented
if we zoom out sufficiently we can see
that things are loaded in different
levels of detail in the folder but the
fill out we get from the position of the
camera a player or whatever you use to
to define as the center of the currently
loaded part of the world the felt the
fill out you go from there the less
information we have so let's try to turn
on some the grid that we're using so
this is the grid that this procedural
generation operation and it actually
eats the way it works is that the
generation works in civil layers so each
layer can have more information but it
requires that all the neighboring then
not the 8 neighbors are loaded up to the
previous layer so let's take it from the
beginning in this case the outermost
cells in the grid the left right and top
and bottom they are loaded to the level
of zero and that means in this case that
in each of these cells I create a list
of three random points within the cell
so that's all we have unless 0 in this
these outermost cells now in the next
layer the problem is for these random
points since they're random they can end
up being
very close to each other and for this
thing we want things to be not very
evenly but at least a little evenly
distributed and it doesn't work well if
some points a way too close to each
other in that case so we want to adjust
the points but we cannot do that as long
as we don't know the neighboring points
in the other cells if we only looked and
adjusted the points compared to other
points in the same cell then they might
just end up being very close to points
in the neighboring cells so before we
can make the adjustments we have to know
about the points in all the neighboring
cells as well so we have a layer one
that's that takes care justing the
points but layer one requires four cell
to be at layer one it first requires
that all the neighboring cells are
loaded two layer zero and once that that
is the case we can adjust these points
and see the old positions amount in gray
and the new adjusted ones a mark in
white the next layer layer one we can
begin to calculate Regis's for the
worlds the radiuses requires that we
know the positions of these worlds as
well as the neighboring walls but it has
to be the final the adjusted positions
not the initial ones so we need to have
all the neighboring cells loaded to
layer one before we can calculate the
radiuses in layer two and then we can do
that lesson randomness as well they get
different sizes and and depending on the
radiuses of of each other they can think
and have different sizes and now the
next layer requires that we already know
the radiuses of all the worlds
and then we can begin to calculate
connections between them what I do in
this case is at first to Dylan a
triangulation of the points and that's
the points in this cell and all the
neighboring cells in order to figure out
which of the points will look natural to
connect but only use this subset of
those I don't want all the connections
to form triangles I want things to be a
bit less connected so you might
sometimes have to take a bit of a detour
in order to get from from one world to
another so use a subset I basically make
sure all the worlds within the cell are
connected to each other but not not that
every planet is connected to every other
one but just that you can get from any
one to the others through maybe a third
one and then I also make sure that
there's a for each of the neighboring
cells there's at least one planet in or
one world in that cell that's connected
to the current cell some planet in the
current cell so that there's some way to
get to the neighboring cells but only
one pass that goes between the cells and
I do that by basically choosing the
shortest path that can connect the
planet in in the neighboring cell and
this cell and that's it then we best the
more layers we have loaded the the more
information we have about about the
surroundings and eventually I calculate
some information within the planets
themselves but that's actually a bit
unrelated to to what we're discussing
here and that's something that would be
used for
when going even more in details and zoom
in on one planet and and it's used to
whatever is actually going on with that
planet itself but that's not needed in
in this context or skip going into
childhood with that but but that's it
and an approach with layers that depends
on lower layers basically means that you
can have infinite a procedural
generation of quite high complexity even
though you don't have any bounds it just
means that the more dependencies you
have between some local data and some
data that's located around it the more
of this kinds of dependencies you have
the more layers you have to have and the
further out the the loaded area will
have to extend but but the furthest
paths can be loaded only at a very low
abstraction level so that's that's the
basics here so these layers are kind of
symbol in that they all use the same
grid size and know about each other it's
a fairly simple pattern here where each
cell just depends on the neighboring
eight other cells but for the game I'm
developing that's one of the approaches
I'm using I'm also using a different
approach with completely decoupled
layers that can have different grid
resolutions and where each layer is
basically unaware of the internal
implementation details of the other
layers and they just ask each other for
information up from some given point in
on our layer and it doesn't care about
what cells are loaded it can basically
treat other layers as just infinite but
that's something for another talk before
we stop here let's just look at the
loading while
assumed out so basically as you move new
layers are new cells layer a loaded in
both everything from layer 0 at the
outmost to and the end the things that
already loaded at LaCie or get get
upgraded to layer 1 and so on so the
sender cells that are at the topmost
layer you get a shifting window of those
and as they move out of the window again
they get unloaded to lower layers
progressively until they're completely
unloaded and this can just go on and on
that's it
you
Weitere ähnliche Videos ansehen
5.0 / 5 (0 votes)