上周我开发了一个世界发电机(用于Minecraft mod)。然而,我并不只是寻找Perlin噪音,而是基于细胞噪音。我想生成一种地下实验室,有几个不同大小的房间。
为了解释这个问题,我使用2D示例。
噪声生成器采用网格单元格位置(int x, int y
),并返回具有此结构的对象:
boolean top;
boolean right;
boolean down;
boolean left;
int roomType;
4个布尔代表启用或禁用的墙:
roomType
分别代表房间的类型。
最终结果应该是这样的:
这里,背景棋盘图案代表基础网格,黑色线条代表墙壁。这只是一个可以生成的简单示例,但在实际情况中,网格在x和y方向都是无限的。
我现在遇到的问题是噪声生成器只接受x和y坐标,这是它应该生成的网格单元的坐标。有一个种子可以为哈希函数生成更多随机种子:
long seed = 0x75fd239de48;
Random r = new Random(seed);
int seed1 = r.nextInt();
int seed2 = r.nextInt();
// etc.
我可以使用哈希函数:Hash.hash2D(int seed, int x, int y)
,根据种子返回一个坐标的随机double
。
这将为周围细胞生成信息。
要轻松生成更大的房间,您可以设置房间的最大尺寸,并检查房间的面积是否大于1x1。如果他们在那里,并将跨越到当前房间,房间将是另一个房间的延伸。但是,检查房间是否会延伸需要检查是否尚未延伸(否则,不需要的房间扩展看起来像是扩展另一个房间的房间基础),这会延伸到无限循环。
在我的情况下,有一个给定的房间类型表,它们的大小和重量。例如:
name: size [weight]
room-1: 1x1 [128]
room-2: 1x1 [128]
room-3: 2x1 [16]
room-4: 1x2 [16]
room-5: 2x2 [8]
room-6: 3x1 [4]
room-7: 1x3 [4]
还有很多其他版本,尺寸最高可达5x5,但我将此示例列表用于我的问题。此示例中的最大尺寸为3x3(仅最大宽度乘以最大高度)。
这里我有一个Java的基本设置示例类:
public class RoomNoise {
private final long seed;
private final Random rand;
public RoomNoise( long seed ) {
this.seed = seed;
this.rand = new Random( seed );
}
public enum RoomTypes {
ROOM1( 1, 1, 128 ),
ROOM2( 1, 1, 128 ),
ROOM3( 2, 1, 16 ),
ROOM4( 1, 2, 16 ),
ROOM5( 2, 2, 8 ),
ROOM6( 1, 3, 4 ),
ROOM7( 3, 1, 4 );
public final int width;
public final int height;
public final int weight;
private RoomTypes( int w, int h, int weight ) {
width = w;
height = h;
this.weight = weight;
}
}
public static class Output {
public final RoomTypes roomType;
public final boolean upWall;
public final boolean rightWall;
public final boolean downWall;
public final boolean leftWall;
public Output( RoomTypes type, boolean u, boolean r, boolean d, boolean l ) {
roomType = type;
upWall = u;
rightWall = r;
downWall = d;
leftWall = l;
}
}
public Output generate( int x, int y ) {
// What should be here
}
}
我正在寻找generate
方法的内容,为此我尝试了很多东西,但每次我变成无限循环或者它都不起作用。
是否有任何方法可以在O(N)
N
小于无穷大的情况下生成此噪音?如果有办法,那是哪种方式,我该如何实施呢?我搜索了互联网并尝试了很多东西(现在已经有3个星期了),但仍未找到解决方案。
我使用Java 1.8,但我更喜欢任何C风格的语言。
同样,我有这个哈希函数:
Hash.hash2D( int seed, int x, int y );
我无法手动加载和删除块(网格单元格),基本API(Minecraft)正在为我做这件事。它只给我一个坐标(这取决于玩家的互动),我应该回放一个(部分)房间,适合该坐标处的块。我也知道,一旦生成了一个块,它就不会再次生成。
答案 0 :(得分:1)
我不确定我是否完全理解您要解决的问题,所以如果这个问题不够,请随时发表评论:
如果您希望能够生成无限网格,那么您将只能够近似无限。我认为你有两个选择:
OR:
答案 1 :(得分:0)
好的,我想我自己已经解决了。
在此网格中,您有一些想要扩展的单元格。这由散列函数直接定义:
但是,某些扩展与其他扩展重叠。这是我们实际上不了解的事情。
优先考虑每个细胞。你可以通过几种方式做到这一点:
只需使用哈希函数为其提供随机优先级
优先考虑每种可能的房型/大小(例如,较大的房间具有较高的优先级)。
优先级仅对想要扩展的单元格很重要。在我的例子中,较大的单元格具有较高的优先级。
好的,知道这一点,你必须做一些步骤。我们知道最大尺寸是3x3。
知道了这一点,我们需要检查一个找到的细胞是否可以扩展到这个细胞。要检查这一点,请检查是否要将此单元格作为扩展名,然后执行以下步骤并将检查单元格作为输入坐标。在该示例中,扩展单元能够扩展。我们也知道扩展单元将扩展输入单元,因此输入单元是扩展。
其他一些例子:
输入坐标。他们都不想要延期:
检查区域:
如您所见,一个单元格找到了一个扩展空间,但该扩展空间并没有扩展该输入单元格。这使得所有这些房间成为1x1房间:
以及如何检查细胞是否可以扩展
做一个艰难的检查。硬检查检查扩展区域(在这种情况下为3x3)大小正好在输入单元格下方,以便其他单元尝试扩展。如果有,请检查是否可以延长。如果可以的话,输入单元不能延伸并继续输入单元上非扩展单元的步骤。为了节省内存和时间,您可以跳过检查找到的单元格是否可以延伸(可能会进入无限循环),然后直接取一个1x1单元格(不需要非扩展单元格步骤)。
在这种情况下,这是扩展区域/硬检查区域。此处没有扩展单元格,因此单元格可以延伸。
现在进行软检查。软检查检查在单元格下方和正上方的最大尺寸区域中扩展单元格:
在这里,您可以检查它们是否确实延伸,但这需要大量的记忆和时间
对于每个找到的单元格,如果它们将延伸到输入单元将延伸的任何扩展单元格,请检查它们正下方的扩展区域。检查两个扩展区域是否重叠。如果他们没有,您的单元格可以延长,您可以跳过步骤3并转到步骤4.如果是,请转到步骤3.在这种情况下,找到重叠:
这里,红色轮廓的黄色单元格是重叠的。
您发现了重叠。在这里,优先事项将发挥作用。取扩展单元的优先级,该区域与输入单元区域重叠。同时取输入单元本身的优先级。比较他们。如果输入单元格的优先级大于另一个优先级,则输入单元格可以扩展,您可以转到步骤4.如果输入单元格的优先级较低,则无法扩展,您可以将其设置为1x1房间(或者您可以执行非扩展单元格步骤,如果您在硬检查中验证找到的单元格,则必须执行此操作)。如果优先级相等,请选择具有最高X或Y坐标的单元格 在我的示例中,输入单元格具有最高优先级,因为它更大。
最后一步。保证细胞延伸。您可以计算存在哪些墙。请注意,左侧和顶部墙始终存在,因为扩展单元始终位于左上角
我们的细胞可以扩展,我们得到这个结果:
另一个例子
实际上,那就是它。我希望我已经足够清楚了。您可以使用矩形,也可以使用更复杂的形状,如L形房间,而不是使用正方形。