如何在 Minecraft 中的圆形或椭圆形生成区域中获取随机离散点?

How to get a random discrete point in a circular or ellipsoid spawn region in Minecraft?

在为 Minecraft 编写了我的第一个随机生成插件后,我立即想升级到允许圆形和椭圆形生成区域作为 select 来自的随机点的有限生成区域。

在给定范围内获取两个随机数,然后将它们四舍五入到最接近的整数,从而在笛卡尔平面上产生一个矩形区域,每个单元都有离散点。

看起来像这样:

// in Util.java
// get a random whole number in range
public static int getRandomNumber(int min, int max) {
    return (int) ((Math.random() * (max - min)) + min);
}

// in the class that controls spawning
// get random x, z co-coordinates within range; refer to the *center* of blocks
double tryLocation_x = Math.rint(Util.getRandomNumber((int)min_x, (int)max_x)) + 0.5;
double tryLocation_z = Math.rint(Util.getRandomNumber((int)min_z, (int)max_z)) + 0.5;

但是如何整合一个有效的椭球面积作为这些离散点的限制范围呢?

我们需要添加一些东西,使我们能够忽略 随机生成的数字,这些数字会出现在 radius_X, radius_Z 定义的椭圆之外。这是因为如前所述,以这种方式生成的坐标会产生有效离散点的有效矩形区域。

经过大量研究和询问,我终于找到了一个简单的解决方案,相对于常规的矩形生成区域,它不会显着影响性能。

让我解释一下。

我遇到的最困难的信息如下:

public static int isInEllipse(int h, int k, int x, int y, int a, int b) {
    // h, k are center point | x, y are co-ords to check | a, b are ellipse radii
    int p = ((int)Math.pow((x - h), 2) / (int)Math.pow(a, 2))
            + ((int)Math.pow((y - k), 2) / (int)Math.pow(b, 2));

    return p;
}

椭圆由它们的两个半径定义;短半径和长半径。不过,再如前所述,这两个随机生成的数字可以在椭圆圆周的外部、内部和顶部产生离散点。

如果坐标在椭圆内,上述方法isInEllipse将return小于1,在圆周上时小于1。否则它们在椭圆之外。


好的,现在我们有一种方法可以检查随机坐标在我们定义的椭圆中的有效性。 让我们开始吧。

// get random x, z co-coordinates within range; refer to the *center* of blocks
double tryLocation_x = Math.rint(Util.getRandomNumber((int)radius_X*-1, (int)radius_X)) + 0.5;
double tryLocation_z = Math.rint(Util.getRandomNumber((int)radius_Z*-1, (int)radius_Z)) + 0.5;
int ellipseCheck = Util.isInEllipse(0, 0, (int)tryLocation_x, (int)tryLocation_z, (int)radius_X, (int)radius_Z);

很好。现在我们有办法创建随机坐标,然后检查它们是否在定义的椭圆区域内。

这样,我们就可以继续循环检查,直到找到有效坐标:

final double spawnLoc_x;
final double spawnLoc_z;

boolean isValidRespawn = false;
while (!isValidRespawn) {
    double tryLocation_x = Math.rint(Util.getRandomNumber((int)radius_X*-1, (int)radius_X)) + 0.5;
    double tryLocation_z = Math.rint(Util.getRandomNumber((int)radius_Z*-1, (int)radius_Z)) + 0.5;
    int ellipseCheck = Util.isInEllipse(0, 0, (int)tryLocation_x, (int)tryLocation_z, (int)radius_X, (int)radius_Z);
    
    if (ellipseCheck > 1) continue;
    else isValidRespawn = true;

    spawnLoc_x = tryLocation_x;
    spawnLoc_z = tryLocation_z;
}

您现在可以改变玩家的 respawn location object with the coordinates you get from this. As for the Y value, you can use World.gethighestBlockAt(int x, int z) 以保持简单。

我花了很多时间寻找这个答案。我希望这个 post 能帮助很多人找到这个解决方案。干杯!

参考: https://www.geeksforgeeks.org/check-if-a-point-is-inside-outside-or-on-the-ellipse/