在为Minecraft编写了我的第一个随机生成插件后,我立即想升级到允许圆形和椭球体生成区域作为有限的生成区域来选择随机点。
在给定范围内获得两个随机数,然后将它们四舍五入到最近的整数,可以有效地在笛卡尔平面上生成一个矩形区域,每个单元都有离散点。
看起来是这样的:
// 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
将返回小于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;
}
你现在可以用你从中得到的坐标来改变玩家的重生位置对象。至于Y值,可以使用World.gethighestBlockAt(int x, int z)
使其保持简单。
我花了很多小时寻找这个答案。我希望这篇文章能帮助很多偷窥者找到这个解决方案。干杯
参考:https://www.geeksforgeeks.org/check-if-a-point-is-inside-outside-or-on-the-ellipse/