152 lines
5.4 KiB
Java
152 lines
5.4 KiB
Java
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 {
|
||
|
||
/**
|
||
* 计算迫击炮理论水平射程
|
||
*
|
||
* @param thetaDegrees 发射角度(以度为单位),需要根据实际情况修改
|
||
* @param v 初始速度
|
||
* @param g 重力加速度
|
||
*/
|
||
public static double getRange(double thetaDegrees, double v, double g) {
|
||
double t = v * Math.sin(thetaDegrees * Mth.DEG_TO_RAD) / g * 2;
|
||
return t * v * Math.cos(thetaDegrees * Mth.DEG_TO_RAD);
|
||
}
|
||
|
||
// 谢谢DeepSeek
|
||
|
||
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;
|
||
|
||
double a = 0.25 * g * g;
|
||
double b = -velocity * velocity - g * dy;
|
||
double c = horizontalDistSq + dy * dy;
|
||
|
||
List<Double> 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);
|
||
}
|
||
|
||
private static List<Double> 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");
|
||
}
|
||
|
||
double sqrtDisc = Math.sqrt(discriminant);
|
||
double u1 = (-b + sqrtDisc) / (2 * a);
|
||
double u2 = (-b - sqrtDisc) / (2 * a);
|
||
|
||
List<Double> 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;
|
||
}
|
||
private static final double TOLERANCE = 1e-3; // 牛顿迭代法的容差
|
||
private static final int MAX_ITERATIONS = 50; // 最大迭代次数
|
||
|
||
/**
|
||
* 计算炮弹发射向量
|
||
* @param launchPos 炮弹发射位置 (Vec3)
|
||
* @param targetPos 目标当前位置 (Vec3)
|
||
* @param targetVel 目标速度向量 (Vec3,单位:方块/tick)
|
||
* @param muzzleVelocity 炮弹出膛速度 (标量,单位:方块/tick)
|
||
* @return 炮弹的发射向量 (Vec3),若无法击中则返回预测值
|
||
*/
|
||
public static Vec3 calculateFiringSolution(Vec3 launchPos, Vec3 targetPos, Vec3 targetVel, double muzzleVelocity, double gravity) {
|
||
Vec3 d0 = targetPos.subtract(launchPos); // 位置差向量
|
||
double D = d0.lengthSqr(); // |d0|²
|
||
double E = d0.dot(targetVel); // d0 · u
|
||
double F = targetVel.lengthSqr(); // |u|²
|
||
|
||
// 计算四次方程的系数
|
||
double a = 0.25 * gravity * gravity;
|
||
double b = gravity * targetVel.y;
|
||
double c = F + gravity * d0.y - muzzleVelocity * muzzleVelocity;
|
||
double d = 2 * E;
|
||
double e = D;
|
||
|
||
// 牛顿迭代法求解时间 t
|
||
double t = estimateInitialTime(d0, muzzleVelocity); // 初始估计值
|
||
double prevT = t;
|
||
|
||
for (int i = 0; i < MAX_ITERATIONS; i++) {
|
||
double t2 = t * t;
|
||
double t3 = t2 * t;
|
||
double t4 = t3 * t;
|
||
|
||
// 计算函数值 f(t) = a*t⁴ + b*t³ + c*t² + d*t + e
|
||
double f = a * t4 + b * t3 + c * t2 + d * t + e;
|
||
if (Math.abs(f) < TOLERANCE) break;
|
||
|
||
// 计算导数值 f'(t) = 4a*t³ + 3b*t² + 2c*t + d
|
||
double df = 4 * a * t3 + 3 * b * t2 + 2 * c * t + d;
|
||
if (Math.abs(df) < 1e-10) {
|
||
t = prevT + 0.1; // 避免除零,调整t
|
||
continue;
|
||
}
|
||
|
||
prevT = t;
|
||
t -= f / df; // 牛顿迭代
|
||
|
||
// 确保t为正数
|
||
if (t < 0) t = 0.1;
|
||
}
|
||
|
||
// 检查解的有效性
|
||
if (t > 0 && !Double.isNaN(t)) {
|
||
double invT = 1.0 / t;
|
||
// 计算速度分量
|
||
double vx = d0.x * invT + targetVel.x;
|
||
double vz = d0.z * invT + targetVel.z;
|
||
double vy = d0.y * invT + targetVel.y + 0.5 * gravity * t;
|
||
return new Vec3(vx, vy, vz);
|
||
} else {
|
||
// 备选方案:线性预测目标位置
|
||
double fallbackT = Math.sqrt(D) / muzzleVelocity;
|
||
Vec3 predictedPos = targetPos.add(targetVel.scale(fallbackT));
|
||
Vec3 toPredicted = predictedPos.subtract(launchPos);
|
||
double vy = (toPredicted.y + 0.5 * gravity * fallbackT * fallbackT) / fallbackT;
|
||
Vec3 horizontal = new Vec3(toPredicted.x, 0, toPredicted.z).normalize();
|
||
double horizontalSpeed = Math.sqrt(muzzleVelocity * muzzleVelocity - vy * vy);
|
||
return new Vec3(
|
||
horizontal.x * horizontalSpeed,
|
||
vy,
|
||
horizontal.z * horizontalSpeed
|
||
);
|
||
}
|
||
}
|
||
|
||
// 初始时间估计(无重力无移动的飞行时间)
|
||
private static double estimateInitialTime(Vec3 d0, double velocity) {
|
||
return d0.length() / velocity;
|
||
}
|
||
|
||
}
|