From c8c141e4bbdd5d8263d9504ccbff301c3bd1e498 Mon Sep 17 00:00:00 2001 From: 17146 <1714673995@qq.com> Date: Sun, 15 Jun 2025 18:56:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E6=B7=BB=E5=8A=A0obb?= =?UTF-8?q?=E4=B8=8Eaabb=E7=9A=84=E7=A2=B0=E6=92=9E=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/projectile/ProjectileEntity.java | 58 +++++++------ .../mixins/EntityRenderDispatcherMixin.java | 2 +- .../atsuishio/superbwarfare/tools/OBB.java | 83 +++++++++++++++++++ 3 files changed, 118 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/ProjectileEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/ProjectileEntity.java index bdd8c7442..bbdb6fcbf 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/ProjectileEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/ProjectileEntity.java @@ -4,6 +4,7 @@ import com.atsuishio.superbwarfare.block.BarbedWireBlock; import com.atsuishio.superbwarfare.component.ModDataComponents; import com.atsuishio.superbwarfare.config.server.ProjectileConfig; import com.atsuishio.superbwarfare.entity.DPSGeneratorEntity; +import com.atsuishio.superbwarfare.entity.OBBEntity; import com.atsuishio.superbwarfare.entity.TargetEntity; import com.atsuishio.superbwarfare.entity.mixin.ICustomKnockback; import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; @@ -155,6 +156,7 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp @Nullable protected List findEntitiesOnPath(Vec3 startVec, Vec3 endVec) { List hitEntities = new ArrayList<>(); + // TODO 换一个允许检测obb的方法 List entities = this.level().getEntities( this, this.getBoundingBox() @@ -179,36 +181,44 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp @Nullable private EntityResult getHitResult(Entity entity, Vec3 startVec, Vec3 endVec) { double expandHeight = entity instanceof Player && !entity.isCrouching() ? 0.0625 : 0.0; - AABB boundingBox = entity.getBoundingBox(); - Vec3 velocity = new Vec3(entity.getX() - entity.xOld, entity.getY() - entity.yOld, entity.getZ() - entity.zOld); - if (entity instanceof ServerPlayer player && this.shooter instanceof ServerPlayer serverPlayerOwner) { - int ping = Mth.floor((serverPlayerOwner.connection.latency() / 1000.0) * 20.0 + 0.5); - boundingBox = HitboxHelper.getBoundingBox(player, ping); - velocity = HitboxHelper.getVelocity(player, ping); - } - boundingBox = boundingBox.expandTowards(0, expandHeight, 0); + Vec3 hitPos; + if (entity instanceof OBBEntity obbEntity) { + OBB obb = obbEntity.getOBB(); + var obbVec = obb.clip(startVec.toVector3f(), endVec.toVector3f()).orElse(null); + if (obbVec == null) return null; + hitPos = new Vec3(obbVec); + } else { + AABB boundingBox = entity.getBoundingBox(); + Vec3 velocity = new Vec3(entity.getX() - entity.xOld, entity.getY() - entity.yOld, entity.getZ() - entity.zOld); - boundingBox = boundingBox.expandTowards(velocity.x, velocity.y, velocity.z); - - double playerHitboxOffset = 3; - if (entity instanceof ServerPlayer) { - if (entity.getVehicle() != null) { - boundingBox = boundingBox.move(velocity.multiply(playerHitboxOffset / 2, playerHitboxOffset / 2, playerHitboxOffset / 2)); + if (entity instanceof ServerPlayer player && this.shooter instanceof ServerPlayer serverPlayerOwner) { + int ping = Mth.floor((serverPlayerOwner.connection.latency() / 1000.0) * 20.0 + 0.5); + boundingBox = HitboxHelper.getBoundingBox(player, ping); + velocity = HitboxHelper.getVelocity(player, ping); } - boundingBox = boundingBox.move(velocity.multiply(playerHitboxOffset, playerHitboxOffset, playerHitboxOffset)); - } + boundingBox = boundingBox.expandTowards(0, expandHeight, 0); + boundingBox = boundingBox.expandTowards(velocity.x, velocity.y, velocity.z); - if (entity.getVehicle() != null) { - boundingBox = boundingBox.move(velocity.multiply(-2.5, -2.5, -2.5)); - } - boundingBox = boundingBox.move(velocity.multiply(-5, -5, -5)); + double playerHitboxOffset = 3; + if (entity instanceof ServerPlayer) { + if (entity.getVehicle() != null) { + boundingBox = boundingBox.move(velocity.multiply(playerHitboxOffset / 2, playerHitboxOffset / 2, playerHitboxOffset / 2)); + } + boundingBox = boundingBox.move(velocity.multiply(playerHitboxOffset, playerHitboxOffset, playerHitboxOffset)); + } - if (this.beast) { - boundingBox = boundingBox.inflate(3); - } + if (entity.getVehicle() != null) { + boundingBox = boundingBox.move(velocity.multiply(-2.5, -2.5, -2.5)); + } + boundingBox = boundingBox.move(velocity.multiply(-5, -5, -5)); - Vec3 hitPos = boundingBox.clip(startVec, endVec).orElse(null); + if (this.beast) { + boundingBox = boundingBox.inflate(3); + } + + hitPos = boundingBox.clip(startVec, endVec).orElse(null); + } if (hitPos == null) { return null; diff --git a/src/main/java/com/atsuishio/superbwarfare/mixins/EntityRenderDispatcherMixin.java b/src/main/java/com/atsuishio/superbwarfare/mixins/EntityRenderDispatcherMixin.java index 603d6e1d3..bb9189706 100644 --- a/src/main/java/com/atsuishio/superbwarfare/mixins/EntityRenderDispatcherMixin.java +++ b/src/main/java/com/atsuishio/superbwarfare/mixins/EntityRenderDispatcherMixin.java @@ -20,7 +20,7 @@ public class EntityRenderDispatcherMixin { at = @At("RETURN")) private static void renderHitbox(PoseStack poseStack, VertexConsumer buffer, Entity p_entity, float red, float green, float blue, float alpha, CallbackInfo ci) { if (p_entity instanceof OBBEntity obbEntity && p_entity instanceof VehicleEntity vehicle) { - OBBRenderer.INSTANCE.render(vehicle, obbEntity.getOBB(), poseStack, buffer, 1, 1, 1, 1, Minecraft.getInstance().getTimer().getRealtimeDeltaTicks()); + OBBRenderer.INSTANCE.render(vehicle, obbEntity.getOBB(), poseStack, buffer, 0, 1, 0, 1, Minecraft.getInstance().getTimer().getRealtimeDeltaTicks()); } } } diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/OBB.java b/src/main/java/com/atsuishio/superbwarfare/tools/OBB.java index 2cc39cc70..06dc4bb54 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/OBB.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/OBB.java @@ -6,6 +6,8 @@ import org.joml.Math; import org.joml.Quaternionf; import org.joml.Vector3f; +import java.util.Optional; + /** * Codes based on @AnECanSaiTin's HitboxAPI * @@ -130,4 +132,85 @@ public record OBB(Vector3f center, Vector3f extents, Quaternionf rotation) { return nearP; } + + public Optional clip(Vector3f pFrom, Vector3f pTo) { + // 计算OBB的局部坐标系基向量(世界坐标系中的方向) + Vector3f[] axes = new Vector3f[3]; + axes[0] = rotation.transform(new Vector3f(1, 0, 0)); + axes[1] = rotation.transform(new Vector3f(0, 1, 0)); + axes[2] = rotation.transform(new Vector3f(0, 0, 1)); + + // 将点转换到OBB局部坐标系 + Vector3f localFrom = worldToLocal(pFrom, axes); + Vector3f localTo = worldToLocal(pTo, axes); + + // 射线方向(局部坐标系) + Vector3f dir = new Vector3f(localTo).sub(localFrom); + + // Slab算法参数 + double tEnter = 0.0; // 进入时间 + double tExit = 1.0; // 离开时间 + + // 在三个轴上执行Slab算法 + for (int i = 0; i < 3; i++) { + double min = -extents.get(i); + double max = extents.get(i); + double origin = localFrom.get(i); + double direction = dir.get(i); + + // 处理射线平行于轴的情况 + if (Math.abs(direction) < 1e-7f) { + if (origin < min || origin > max) { + return Optional.empty(); + } + continue; + } + + // 计算与两个平面的交点参数 + double t1 = (min - origin) / direction; + double t2 = (max - origin) / direction; + + // 确保tNear是近平面,tFar是远平面 + double tNear = Math.min(t1, t2); + double tFar = Math.max(t1, t2); + + // 更新进入/离开时间 + if (tNear > tEnter) tEnter = tNear; + if (tFar < tExit) tExit = tFar; + + // 检查是否提前退出(无交点) + if (tEnter > tExit) { + return Optional.empty(); + } + } + + // 检查是否有有效交点 + if (tEnter >= 0 && tEnter <= 1) { + // 计算局部坐标系中的交点 + Vector3f localHit = new Vector3f(dir).mul((float) tEnter).add(localFrom); + // 转换回世界坐标系 + return Optional.of(localToWorld(localHit, axes)); + } + + return Optional.empty(); + } + + // 世界坐标转局部坐标 + private Vector3f worldToLocal(Vector3f worldPoint, Vector3f[] axes) { + Vector3f rel = new Vector3f(worldPoint).sub(center); + return new Vector3f( + rel.dot(axes[0]), + rel.dot(axes[1]), + rel.dot(axes[2]) + ); + } + + // 局部坐标转世界坐标 + private Vector3f localToWorld(Vector3f localPoint, Vector3f[] axes) { + Vector3f result = new Vector3f(center); + result.add(axes[0].mul(localPoint.x, new Vector3f())); + result.add(axes[1].mul(localPoint.y, new Vector3f())); + result.add(axes[2].mul(localPoint.z, new Vector3f())); + return result; + } }