(Java) 向量问题 - 检查怪物是否在 3 个向量中

(Java) Vector problems - Check if a monster is inside 3 Vectors

目前我拥有所有需要的工具,除了向量和检查生物是否在实际三角形内。如果您想了解更多详细信息,请查看所附图片。不用担心圆圈,我已经知道了。

目前我的代码是这样的:

public void cleaveCone(Player damager, LivingEntity victim, int level) {
    for(Entity lentity : damager.getNearbyEntities(3, 2, 3)) {
        if(!(lentity instanceof LivingEntity)) continue;
        LivingEntity entity = (LivingEntity) lentity;
    }
}

目前我需要三角形的3个向量,我需要检查它们是否在三角形内,圆圈已经被覆盖,在代码中,僵尸是实体,玩家是破坏者.

创建 Polygon 并检查。 更正:使用 JavaFX Polygon - 双点。

更底层:三角形有三个向量 a -> b -> c -> a 并检查与点向量的 in 乘积是否都是正值等。

要获得三角形的三个坐标或顶点,您可以使用一些三角函数和玩家的 yaw。根据你的图像,三角形的一个顶点是玩家的Location。那个点三角形的内部angle和一个length,它定义了三角形两侧突出玩家的长度,定义了整个三角形。当这两个值都定义好后,我们就可以找到三角形剩下的两个顶点的坐标了。这是一个粗略的草图:

如何获取两个顶点的Locations的例子:

double angle = 90; // An example angle of 90 degrees
double length = 5; // An example length of 5

Location v1 = player.getLocation(); // The first vertex of the triangle, the player's location

double yaw = v1.getYaw(); // The player's yaw (in degrees) between 0º and 360º

World world = player.getWorld(); // The player's world

Location v2 = new Location(world, (-Math.sin(Math.toRadians(yaw - (angle / 2))) * distance) + v1.getX(), 0, (Math.cos(Math.toRadians(yaw - (angle / 2))) * distance) + v1.getZ()); // The second vertex
Location v3 = new Location(world, (-Math.sin(Math.toRadians(yaw + (angle / 2))) * distance) + v1.getX(), 0, (Math.cos(Math.toRadians(yaw + (angle / 2))) * distance) + v1.getZ()); // The third vertex

以弧度为单位的角度的负正弦用于 X 坐标,而以弧度为单位的角度的余弦用于 Z 坐标。

我用了一些粒子来可视化 Minecraft 中三角形的线条,这个三角形的长度为 5,角度为 90 度:

您可以使用一种方法来检查一个点是否在二维三角形内作为对此 question 的答案并使用重心坐标。这是适用于 Bukkit/Spigot.

的示例方法
// v1, v2 and v3 are the vertices of the triangle, in no specific order
// The Y coordinates are ignored (two dimensional)
public static boolean isLocationInTriangle(Location location, Location v1, Location v2, Location v3) {
    // Bunch of math...
    double a = 0.5 * (-v2.getZ() * v3.getX() + v1.getZ() * (-v2.getX() + v3.getX()) + v1.getX() * (v2.getZ() - v3.getZ()) + v2.getX() * v3.getZ());
    int sign = a < 0 ? -1 : 1;
    double s = (v1.getZ() * v3.getX() - v1.getX() * v3.getZ() + (v3.getZ() - v1.getZ()) * location.getX() + (v1.getX() - v3.getX()) * location.getZ()) * sign;
    double t = (v1.getX() * v2.getZ() - v1.getZ() * v2.getX() + (v1.getZ() - v2.getZ()) * location.getX() + (v2.getX() - v1.getX()) * location.getZ()) * sign;

    return s > 0 && t > 0 && (s + t) < 2 * a * sign;
}

我对此进行了一些测试,它似乎运行良好。

您可以像这样在您的方法中使用它:

List<Entity> nearbyEntities = player.getNearbyEntities(8, 2, 8); // Get entities within 16x4x16 box centered around player
for (Entity entity : nearbyEntities) { // For each Entity found
    if (entity instanceof LivingEntity) { // If the Entity is an instance of a LivingEntity
        LivingEntity living = (LivingEntity) entity; // Cast
        if (isLocationInTriangle(living.getLocation(), player.getLocation(), v2, v3)) { // If the LivingEntity is inside the triangle
            living.damage(6); // Damage the entity (just as an example)
        }
    }
}

请注意,即使 IsLocationInTriangle 方法忽略 Y 坐标或高度(因为它是二维检查),getNearbyEntities 方法也会查找框内的实体,在此示例中盒子有 4 个方块的高度,中心在玩家的位置。因此不会检查玩家上方或下方超过 2 个方块的实体。

或者,一旦你有了三角形的三个坐标 v1v2v3,你当然也可以使用它们来创建一个 JavaFX Polygon 就像 Joop 提到的那样,并使用它的 contains 方法来检查实体是否在三角形内,而不是使用重心坐标方法。