噪音产生:'室内噪音'

时间:2018-05-07 19:12:42

标签: java noise-generator

上周我开发了一个世界发电机(用于Minecraft mod)。然而,我并不只是寻找Perlin噪音,而是基于细胞噪音。我想生成一种地下实验室,有几个不同大小的房间。

为了解释这个问题,我使用2D示例。

噪声生成器采用网格单元格位置(int x, int y),并返回具有此结构的对象:

boolean top;
boolean right;
boolean down;
boolean left;

int roomType;

4个布尔代表启用或禁用的墙:

roomType分别代表房间的类型。

最终结果应该是这样的: enter image description here
这里,背景棋盘图案代表基础网格,黑色线条代表墙壁。这只是一个可以生成的简单示例,但在实际情况中,网格在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 );

编辑:

预期结果:
enter image description here
蓝线是走廊,后来生成。忘了他们。

注意:

我无法手动加载和删除块(网格单元格),基本API(Minecraft)正在为我做这件事。它只给我一个坐标(这取决于玩家的互动),我应该回放一个(部分)房间,适合该坐标处的块。我也知道,一旦生成了一个块,它就不会再次生成。

2 个答案:

答案 0 :(得分:1)

我不确定我是否完全理解您要解决的问题,所以如果这个问题不够,请随时发表评论:

如果您希望能够生成无限网格,那么您将只能够近似无限。我认为你有两个选择:

  1. 生成“足够大”的网格。这可能是时间/空间密集的,但是如果你需要多少就有上限,并且一次完成这一切是可行的,那么这是最简单的选择。例如。如果用户不能使距离中心1000多个方格,则生成2000x2000。
  2. OR:

    1. 使用延迟评估。这意味着,在您需要之前不要生成任何东西。如果用户靠近尚未生成的区域,则生成它。另一方面,如果您需要释放资源,您还可以丢弃用户不太可能返回的旧部件。例如:将您的区域切割成正方形(例如20x20或1000x1000),并在玩家靠近它们时生成其他相邻的正方形,或者根据需要将地图平移到该方向等等。

答案 1 :(得分:0)

好的,我想我自己已经解决了。

这是网格,在这里不是无限的,但它可能是。
enter image description here

在此网格中,您有一些想要扩展的单元格。这由散列函数直接定义:
enter image description here
但是,某些扩展与其他扩展重叠。这是我们实际上不了解的事情。

优先考虑每个细胞。你可以通过几种方式做到这一点:

  • 只需使用哈希函数为其提供随机优先级

  • 优先考虑每种可能的房型/大小(例如,较大的房间具有较高的优先级)。

优先级仅对想要扩展的单元格很重要。在我的例子中,较大的单元格具有较高的优先级。

然后我们有输入坐标,即蓝色单元格:
enter image description here

好的,知道这一点,你必须做一些步骤。我们知道最大尺寸是3x3。

如果输入单元格不想扩展

  1. 如果有任何单元格试图延伸到此单元格,请检查最大尺寸区域:
    enter image description here
    在这种情况下它存在。

  2. 知道了这一点,我们需要检查一个找到的细胞是否可以扩展到这个细胞。要检查这一点,请检查是否要将此单元格作为扩展名,然后执行以下步骤并将检查单元格作为输入坐标。在该示例中,扩展单元能够扩展。我们也知道扩展单元将扩展输入单元,因此输入单元是扩展。

  3. 现在我们可以轻松检查哪些墙存在,哪些不存在。在这种情况下,每个墙都消失了,因为它是这个延伸房间的中心:
    enter image description here

  4. 其他一些例子:

    输入坐标。他们都不想要延期:
    enter image description here
    检查区域:
    enter image description here
    如您所见,一个单元格找到了一个扩展空间,但该扩展空间并没有扩展该输入单元格。这使得所有这些房间成为1x1房间:
    enter image description here

    如果输入单元格想要扩展

    以及如何检查细胞是否可以扩展

    1. 做一个艰难的检查。硬检查检查扩展区域(在这种情况下为3x3)大小正好在输入单元格下方,以便其他单元尝试扩展。如果有,请检查是否可以延长。如果可以的话,输入单元不能延伸并继续输入单元上非扩展单元的步骤。为了节省内存和时间,您可以跳过检查找到的单元格是否可以延伸(可能会进入无限循环),然后直接取一个1x1单元格(不需要非扩展单元格步骤)。
      在这种情况下,这是扩展区域/硬检查区域。此处没有扩展单元格,因此单元格可以延伸。
      enter image description here

    2. 现在进行软检查。软检查检查在单元格下方和正上方的最大尺寸区域中扩展单元格:
      enter image description here
      在这里,您可以检查它们是否确实延伸,但这需要大量的记忆和时间 对于每个找到的单元格,如果它们将延伸到输入单元将延伸的任何扩展单元格,请检查它们正下方的扩展区域。检查两个扩展区域是否重叠。如果他们没有,您的单元格可以延长,您可以跳过步骤3并转到步骤4.如果是,请转到步骤3.在这种情况下,找到重叠:
      enter image description here
      这里,红色轮廓的黄色单元格是重叠的。

    3. 您发现了重叠。在这里,优先事项将发挥作用。取扩展单元的优先级,该区域与输入单元区域重叠。同时取输入单元本身的优先级。比较他们。如果输入单元格的优先级大于另一个优先级,则输入单元格可以扩展,您可以转到步骤4.如果输入单元格的优先级较低,则无法扩展,您可以将其设置为1x1房间(或者您可以执行非扩展单元格步骤,如果您在硬检查中验证找到的单元格,则必须执行此操作)。如果优先级相等,请选择具有最高X或Y坐标的单元格 在我的示例中,输入单元格具有最高优先级,因为它更大。

    4. 最后一步。保证细胞延伸。您可以计算存在哪些墙。请注意,左侧和顶部墙始终存在,因为扩展单元始终位于左上角 我们的细胞可以扩展,我们得到这个结果:
      enter image description here

    5. 另一个例子

      输入单元格:
      enter image description here
      做一下硬盘检查:
      enter image description here
      哦,它找到了一个,所以它无法延伸并变成一个1x1的房间:
      enter image description here

      实际上,那就是它。我希望我已经足够清楚了。您可以使用矩形,也可以使用更复杂的形状,如L形房间,而不是使用正方形。

      这是我的例子的最终结果:
      enter image description here