vector - Bukkit/Spigot - 命中检测的弹丸位置完全错误
问题描述
我正在为我的世界服务器制作一个自定义的“枪”插件。我的问题是,当试图检测弹丸降落的位置时,弹丸和被击中的玩家之间的位置差异太大而无法通过我的爆头方法检测到。我对“isHeadshot”使用弹丸跟踪的唯一原因是调试试验。
这是我的拍摄方法
public void shootGun(Player p) {
if (getFirearmAction().isDelayed(p))
return;
double shiftYaw = (p.getLocation().getYaw() + 180) * (Math.PI/180);
Vector shiftVec = new Vector(Math.cos(shiftYaw), 0.0D, Math.sin(shiftYaw)); //TODO: add bullet_spread
for (int i = 0; i < projectileInfo.getAmount(); i++) {
Projectile proj = (Projectile)p.getWorld().spawn(p.getEyeLocation().toVector().add(shiftVec.multiply(0.2D)).toLocation(p.getWorld()), getProjectileInfo().getProjectileClass());
proj.setVelocity(UtilMethods.getBulletVelocity(p).multiply(projectileInfo.getSpeed()));
proj.setShooter(p);
}
projectileInfo.playShootGunSound(p);
getFirearmAction().performAction(p);
}
这是“命中”的侦听器
@EventHandler
public void onEntDamage(EntityDamageByEntityEvent event) {
if (event.getDamager() instanceof Projectile) {
Projectile p = (Projectile)event.getDamager();
if (p.getShooter() instanceof Player) {
Player player = (Player)p.getShooter();
Gun gun = UtilMethods.getGun(player);
if (gun != null) {
int damage = gun.getProjectileInfo().getDamage();
if (event.getEntity() instanceof Player) {
Player ent = (Player)event.getEntity();
if (UtilMethods.isHeadShot(ent, p))
damage *= 2;
}
event.setDamage(damage);
}
}
}
}
最后,这是 [isHeadshot、isInCuboid 和 bulletVelocity] 方法。前两个是尝试找出失败的爆头检测的替代方法... getBulletVelocity 方法设置弹丸的正确速度和方向。(在这种情况下,我正在使用 Snowball.class)
public static boolean isHeadShot(Player victim, Projectile projectile) {
Location locA = new Location(victim.getWorld(), victim.getEyeLocation().getX() -0.5, victim.getEyeLocation().getY() - 0.5, victim.getEyeLocation().getZ() - 0.5);
Location locB = new Location(victim.getWorld(), victim.getEyeLocation().getX() +0.5, victim.getEyeLocation().getY() + 0.5, victim.getEyeLocation().getZ() + 0.5);
for (double i = 0; i < 256; i+=0.8D) {
System.out.println(projectile.getLocation() + " | " + victim.getLocation());
projectile.getLocation().add(projectile.getVelocity().normalize().multiply(i));
if (isInCuboid(locA, locB, projectile.getLocation())) {
System.out.println(i);
return true;
}
}
return false;
}
public static boolean isInCuboid(Location min, Location max, Location varying) {
double[] locs = new double[2];
locs[0] = min.getX();
locs[1] = max.getX();
Arrays.sort(locs);
if (varying.getX() > locs[1] || varying.getX() < locs[0])
return false;
locs[0] = min.getY();
locs[1] = max.getY();
Arrays.sort(locs);
if (varying.getY() > locs[1] || varying.getY() < locs[0])
return false;
locs[0] = min.getZ();
locs[1] = max.getZ();
Arrays.sort(locs);
if (varying.getZ() > locs[1] || varying.getZ() < locs[0])
return false;
return true;
}
public static Vector getBulletVelocity(Player shooter) {
double yaw = Math.toRadians((-shooter.getLocation().getYaw() - 90.0f));
double pitch = Math.toRadians(-shooter.getLocation().getPitch());
double x = Math.cos(pitch) * Math.cos(yaw);
double y = Math.sin(pitch);
double z = -Math.sin(yaw) * Math.cos(pitch);
Vector dirVec = new Vector(x, y, z).normalize();
return dirVec;
}
我需要一些帮助,因为当子弹造成伤害时,子弹似乎已经穿过了玩家的碰撞箱,并且不再被检测为爆头。有什么建议吗?
这就是位置差异。第一个位置是弹丸,第二个位置是受害者。然而,为了击中,子弹必须在某一时刻穿过玩家。
[08:53:22] [服务器线程/INFO]: Location{world=CraftWorld{name=San_Andreas},x=2501.8249706725665,y=73.62000000476837,z=1681.0750064188326,pitch=0.0,yaw=0.0} | 位置{world=CraftWorld{name=San_Andreas},x=2508.7144181513295,y=72.0,z=1671.9424013003206,pitch=0.3,yaw=-8.100003}
解决方案
监听ProjectileHitEvent并检查弹丸的 y 坐标是否在命中玩家眼睛位置的 y 坐标的一定距离内(x 和 z 坐标与确定玩家的爆头无关)。
推荐阅读
- python - 如何在一行中有来自 2 个不同功能的 2 个输出?
- r - 如何在同一张图中绘制 2 个条形图
- javascript - 如何降低 if/else 复杂性?
- python-3.x - 重新排列字符串以制作新字符串
- batch-file - 在批处理文件中使用 icacls(括号问题)
- python - Django - 注释字典在模板中无法正确显示
- docker-compose - Windows 10 上的 Docker-compose:致命 Python 错误:Py_Initialize:无法加载文件系统编解码器
- vba - VBA 根据上面的内容行自动隐藏/取消隐藏行
- vba - 从特定单元格中选择一个范围,然后使用 VBA 特殊粘贴该范围
- php - 像单独的行一样将数组插入数据库