From acbbc1bff422e0dc843dd9dda6ab52266c67b5e0 Mon Sep 17 00:00:00 2001 From: Atsuishio <842960157@qq.com> Date: Sat, 28 Jun 2025 13:57:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=81=AB=E7=82=AE=E5=BC=B9?= =?UTF-8?q?=E9=81=93=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/vehicle/Mk42Entity.java | 57 +++++++++---- .../entity/vehicle/Mle1934Entity.java | 57 +++++++++---- .../entity/vehicle/MortarEntity.java | 26 +++--- .../superbwarfare/tools/RangeTool.java | 81 ++++++++++--------- 4 files changed, 139 insertions(+), 82 deletions(-) diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mk42Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mk42Entity.java index 8d7adce53..2a1e02316 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mk42Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mk42Entity.java @@ -16,9 +16,14 @@ import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.item.common.ammo.CannonShellItem; import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage; -import com.atsuishio.superbwarfare.tools.*; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.InventoryTool; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.atsuishio.superbwarfare.tools.SoundTool; +import net.minecraft.ChatFormatting; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; @@ -51,6 +56,8 @@ import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.animation.*; import software.bernie.geckolib.util.GeckoLibUtil; +import static com.atsuishio.superbwarfare.tools.RangeTool.calculateLaunchVector; + public class Mk42Entity extends VehicleEntity implements GeoEntity, CannonEntity { public static final EntityDataAccessor COOL_DOWN = SynchedEntityData.defineId(Mk42Entity.class, EntityDataSerializers.INT); @@ -123,15 +130,6 @@ public class Mk42Entity extends VehicleEntity implements GeoEntity, CannonEntity public @NotNull InteractionResult interact(Player player, @NotNull InteractionHand hand) { ItemStack stack = player.getMainHandItem(); - if (player.getMainHandItem().getItem() == ModItems.FIRING_PARAMETERS.get() && player.isCrouching()) { - setTarget(player.getMainHandItem()); - return InteractionResult.SUCCESS; - } - if (player.getOffhandItem().getItem() == ModItems.FIRING_PARAMETERS.get() && player.isCrouching()) { - setTarget(player.getOffhandItem()); - return InteractionResult.SUCCESS; - } - if (stack.getItem() instanceof CannonShellItem) { if (this.entityData.get(COOL_DOWN) == 0) { var weaponType = stack.is(ModItems.AP_5_INCHES.get()) ? 0 : 1; @@ -140,12 +138,31 @@ public class Mk42Entity extends VehicleEntity implements GeoEntity, CannonEntity } return InteractionResult.SUCCESS; } + + if (player.getMainHandItem().getItem() == ModItems.FIRING_PARAMETERS.get()) { + if (setTarget(player.getMainHandItem())) { + player.swing(InteractionHand.MAIN_HAND); + return InteractionResult.SUCCESS; + } else { + player.displayClientMessage(Component.translatable("tips.superbwarfare.mortar.warn").withStyle(ChatFormatting.RED), true); + return InteractionResult.FAIL; + } + } + if (player.getOffhandItem().getItem() == ModItems.FIRING_PARAMETERS.get()) { + if (setTarget(player.getOffhandItem())) { + player.swing(InteractionHand.OFF_HAND); + return InteractionResult.SUCCESS; + } else { + player.displayClientMessage(Component.translatable("tips.superbwarfare.mortar.warn").withStyle(ChatFormatting.RED), true); + return InteractionResult.FAIL; + } + } return super.interact(player, hand); } - public void setTarget(ItemStack stack) { + public boolean setTarget(ItemStack stack) { var parameters = stack.get(ModDataComponents.FIRING_PARAMETERS); - if (parameters == null) return; + if (parameters == null) return false; var pos = parameters.pos(); int targetX = pos.getX(); @@ -157,11 +174,19 @@ public class Mk42Entity extends VehicleEntity implements GeoEntity, CannonEntity Vector4f worldPosition = transformPosition(transform, 0f, 2.16f, 0.5175f); Vec3 shootPos = new Vec3(worldPosition.x, worldPosition.y, worldPosition.z); - if (!RangeTool.canReach(15, shellGravity, shootPos, new Vec3(targetX, targetY, targetZ), -14.9, 85, isDepressed)) - return; + try { + Vec3 launchVector = calculateLaunchVector(shootPos, new Vec3(targetX, targetY, targetZ), 15, -shellGravity, isDepressed); + this.look(new Vec3(targetX, targetY, targetZ)); + float angle = (float) -getXRotFromVector(launchVector); + if (angle < -85 || angle > 14.9) { + return false; + } + entityData.set(PITCH, angle); + } catch (Exception e) { + return false; + } - this.look(new Vec3(targetX, targetY, targetZ)); - entityData.set(PITCH, (float) -RangeTool.calculateAngle(15, shellGravity, shootPos, new Vec3(targetX, targetY, targetZ), isDepressed)); + return true; } private void look(Vec3 pTarget) { diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mle1934Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mle1934Entity.java index 6724ddac7..b0160330a 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mle1934Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mle1934Entity.java @@ -16,9 +16,14 @@ import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.item.common.ammo.CannonShellItem; import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage; -import com.atsuishio.superbwarfare.tools.*; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.InventoryTool; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.atsuishio.superbwarfare.tools.SoundTool; +import net.minecraft.ChatFormatting; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; @@ -51,6 +56,8 @@ import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.animation.*; import software.bernie.geckolib.util.GeckoLibUtil; +import static com.atsuishio.superbwarfare.tools.RangeTool.calculateLaunchVector; + public class Mle1934Entity extends VehicleEntity implements GeoEntity, CannonEntity { public static final EntityDataAccessor COOL_DOWN = SynchedEntityData.defineId(Mle1934Entity.class, EntityDataSerializers.INT); @@ -126,15 +133,6 @@ public class Mle1934Entity extends VehicleEntity implements GeoEntity, CannonEnt public @NotNull InteractionResult interact(Player player, @NotNull InteractionHand hand) { ItemStack stack = player.getMainHandItem(); - if (player.getMainHandItem().getItem() == ModItems.FIRING_PARAMETERS.get() && player.isCrouching()) { - setTarget(player.getMainHandItem()); - return InteractionResult.SUCCESS; - } - if (player.getOffhandItem().getItem() == ModItems.FIRING_PARAMETERS.get() && player.isCrouching()) { - setTarget(player.getOffhandItem()); - return InteractionResult.SUCCESS; - } - if (stack.getItem() instanceof CannonShellItem) { if (this.entityData.get(COOL_DOWN) == 0) { var weaponType = stack.is(ModItems.AP_5_INCHES.get()) ? 0 : 1; @@ -143,12 +141,31 @@ public class Mle1934Entity extends VehicleEntity implements GeoEntity, CannonEnt } return InteractionResult.SUCCESS; } + + if (player.getMainHandItem().getItem() == ModItems.FIRING_PARAMETERS.get()) { + if (setTarget(player.getMainHandItem())) { + player.swing(InteractionHand.MAIN_HAND); + return InteractionResult.SUCCESS; + } else { + player.displayClientMessage(Component.translatable("tips.superbwarfare.mortar.warn").withStyle(ChatFormatting.RED), true); + return InteractionResult.FAIL; + } + } + if (player.getOffhandItem().getItem() == ModItems.FIRING_PARAMETERS.get()) { + if (setTarget(player.getOffhandItem())) { + player.swing(InteractionHand.OFF_HAND); + return InteractionResult.SUCCESS; + } else { + player.displayClientMessage(Component.translatable("tips.superbwarfare.mortar.warn").withStyle(ChatFormatting.RED), true); + return InteractionResult.FAIL; + } + } return super.interact(player, hand); } - public void setTarget(ItemStack stack) { + public boolean setTarget(ItemStack stack) { var parameters = stack.get(ModDataComponents.FIRING_PARAMETERS); - if (parameters == null) return; + if (parameters == null) return false; var pos = parameters.pos(); int targetX = pos.getX(); @@ -161,11 +178,19 @@ public class Mle1934Entity extends VehicleEntity implements GeoEntity, CannonEnt Vector4f worldPosition = transformPosition(transform, 0, 1.4992625f, 1.52065f); Vec3 shootPos = new Vec3(worldPosition.x, worldPosition.y, worldPosition.z); - if (!RangeTool.canReach(15, shellGravity, shootPos, new Vec3(targetX, targetY, targetZ), -2.7, 30, isDepressed)) - return; + try { + Vec3 launchVector = calculateLaunchVector(shootPos, new Vec3(targetX, targetY, targetZ), 15, -shellGravity, isDepressed); + this.look(new Vec3(targetX, targetY, targetZ)); + float angle = (float) -getXRotFromVector(launchVector); + if (angle < -30 || angle > 2.7) { + return false; + } + entityData.set(PITCH, angle); + } catch (Exception e) { + return false; + } - this.look(new Vec3(targetX, targetY, targetZ)); - entityData.set(PITCH, (float) -RangeTool.calculateAngle(15, shellGravity, shootPos, new Vec3(targetX, targetY, targetZ), isDepressed)); + return true; } private void look(Vec3 pTarget) { diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/MortarEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/MortarEntity.java index 2af1a7c16..4228c0676 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/MortarEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/MortarEntity.java @@ -8,7 +8,6 @@ import com.atsuishio.superbwarfare.init.ModEntities; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.item.common.ammo.MortarShell; -import com.atsuishio.superbwarfare.tools.RangeTool; import net.minecraft.ChatFormatting; import net.minecraft.commands.arguments.EntityAnchorArgument; import net.minecraft.core.particles.ParticleTypes; @@ -37,6 +36,8 @@ import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.animation.*; import software.bernie.geckolib.util.GeckoLibUtil; +import static com.atsuishio.superbwarfare.tools.RangeTool.calculateLaunchVector; + public class MortarEntity extends VehicleEntity implements GeoEntity { public static final EntityDataAccessor FIRE_TIME = SynchedEntityData.defineId(MortarEntity.class, EntityDataSerializers.INT); @@ -110,8 +111,8 @@ public class MortarEntity extends VehicleEntity implements GeoEntity { Level level = this.level(); if (level instanceof ServerLevel server) { MortarShellEntity entityToSpawn = shell.createShell(player, level, stack); - entityToSpawn.setPos(this.getX(), this.getY() + this.getEyeY(), this.getZ()); - entityToSpawn.shoot(this.getLookAngle().x, this.getLookAngle().y, this.getLookAngle().z, 11.4f, 0.1f); + entityToSpawn.setPos(this.getX(), this.getEyeY(), this.getZ()); + entityToSpawn.shoot(this.getLookAngle().x, this.getLookAngle().y, this.getLookAngle().z, 11.4f, (float) 0.5); level.addFreshEntity(entityToSpawn); server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, (this.getX() + 3 * this.getLookAngle().x), (this.getY() + 0.1 + 3 * this.getLookAngle().y), (this.getZ() + 3 * this.getLookAngle().z), 8, 0.4, 0.4, 0.4, 0.007); @@ -161,19 +162,18 @@ public class MortarEntity extends VehicleEntity implements GeoEntity { double targetZ = pos.getZ(); var isDepressed = parameters.isDepressed(); - if (!RangeTool.canReach(11.4, 0.146, this.getEyePosition(), new Vec3(targetX, targetY, targetZ), 20, 89, isDepressed)) { + try { + Vec3 launchVector = calculateLaunchVector(getEyePosition(), new Vec3(targetX, targetY, targetZ), 11.4, -0.146, isDepressed); + this.look(new Vec3(targetX, targetY, targetZ)); + float angle = (float) -getXRotFromVector(launchVector); + if (angle < -89 || angle > -20) { + return false; + } + entityData.set(PITCH, angle); + } catch (Exception e) { return false; } - this.look(new Vec3(targetX, targetY, targetZ)); - - entityData.set(PITCH, (float) -RangeTool.calculateAngle( - 11.4, 0.146, - this.getEyePosition(), - new Vec3(targetX, targetY, targetZ), - parameters.isDepressed() - )); - return true; } diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/RangeTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/RangeTool.java index 036d7bd23..42b7464bb 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/RangeTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/RangeTool.java @@ -3,6 +3,10 @@ package com.atsuishio.superbwarfare.tools; import net.minecraft.util.Mth; import net.minecraft.world.phys.Vec3; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + public class RangeTool { /** @@ -19,48 +23,51 @@ public class RangeTool { // 谢谢DeepSeek - /** - * 判断按指定参数发射是否可以击中目标 - * - * @param v 初始速度 - * @param g 重力加速度 - * @param startPos 起始位置 - * @param endPos 目标位置 - * @param minAngle 最小仰角 - * @param maxAngle 最大仰角 - * @param isDepressedTrajectory 是否使用低伸弹道 - */ - public static boolean canReach(double v, double g, Vec3 startPos, Vec3 endPos, double minAngle, double maxAngle, boolean isDepressedTrajectory) { - if (getD(v, g, startPos, endPos) < 0) return false; + public static Vec3 calculateLaunchVector(Vec3 pos, Vec3 pos2, double velocity, double g, boolean isDepressed) { + double dx = pos2.x - pos.x; + double dy = pos2.y - pos.y; + double dz = pos2.z - pos.z; + double horizontalDistSq = dx * dx + dz * dz; - var targetAngle = calculateAngle(v, g, startPos, endPos, isDepressedTrajectory); - return targetAngle >= minAngle && targetAngle <= maxAngle; + double a = 0.25 * g * g; + double b = -velocity * velocity - g * dy; + double c = horizontalDistSq + dy * dy; + + List validT = getDoubles(b, a, c); + + double t; + + if (isDepressed) { + t = Collections.min(validT); + } else { + t = Collections.max(validT); + } + + double vx = dx / t; + double vz = dz / t; + double vy = (dy - 0.5 * g * t * t) / t; + + return new Vec3(vx, vy, vz); } - /** - * 计算按指定参数发射所需的仰角 - * - * @param v 初始速度 - * @param g 重力加速度 - * @param startPos 起始位置 - * @param endPos 目标位置 - * @param isDepressedTrajectory 是否使用低伸弹道 - */ - public static double calculateAngle(double v, double g, Vec3 startPos, Vec3 endPos, boolean isDepressedTrajectory) { - var xDiff = startPos.x - endPos.x; - var zDiff = startPos.z - endPos.z; - var x = Math.sqrt(Math.pow(xDiff, 2) + Math.pow(zDiff, 2)); - double d = getD(v, g, startPos, endPos); - return Math.atan((v * v + (isDepressedTrajectory ? -d : d)) / (g * x)) * Mth.RAD_TO_DEG; - } + private static List getDoubles(double b, double a, double c) { + double discriminant = b * b - 4 * a * c; + if (discriminant < 0) { + throw new IllegalStateException("No valid trajectory: Increase velocity or adjust target"); + } - private static double getD(double v, double g, Vec3 startPos, Vec3 endPos) { - var xDiff = startPos.x - endPos.x; - var zDiff = startPos.z - endPos.z; - var x = Math.sqrt(Math.pow(xDiff, 2) + Math.pow(zDiff, 2)); - var y = startPos.y - endPos.y; + double sqrtDisc = Math.sqrt(discriminant); + double u1 = (-b + sqrtDisc) / (2 * a); + double u2 = (-b - sqrtDisc) / (2 * a); - return Math.sqrt(Math.pow(v, 4) - g * g * x * x - 2 * g * y * v * v); + List validT = new ArrayList<>(); + if (u1 > 0) validT.add(Math.sqrt(u1)); + if (u2 > 0) validT.add(Math.sqrt(u2)); + + if (validT.isEmpty()) { + throw new IllegalStateException("No positive real solution for flight time"); + } + return validT; } }