优化火控计算
This commit is contained in:
parent
b6e58c411a
commit
086b6784e8
2 changed files with 88 additions and 6 deletions
|
@ -298,19 +298,22 @@ public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEnti
|
||||||
this.entityData.set(TARGET_UUID, target.getVehicle().getStringUUID());
|
this.entityData.set(TARGET_UUID, target.getVehicle().getStringUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 targetPos = new Vec3(target.getX(), target.getY() + target.getBbHeight() / 4, target.getZ()).add(target.getDeltaMovement().scale(1.0 + 0.04 * target.distanceTo(this)));
|
Vec3 targetPos = target.getBoundingBox().getCenter();
|
||||||
Vec3 targetVec = barrelRootPos.vectorTo(targetPos).normalize();
|
Vec3 targetVel = target.getDeltaMovement();
|
||||||
|
|
||||||
|
Vec3 targetVec = RangeTool.calculateFiringSolution(barrelRootPos, targetPos, targetVel, 30, 0.03);
|
||||||
|
|
||||||
double d0 = targetVec.x;
|
double d0 = targetVec.x;
|
||||||
double d1 = targetVec.y;
|
double d1 = targetVec.y;
|
||||||
double d2 = targetVec.z;
|
double d2 = targetVec.z;
|
||||||
double d3 = Math.sqrt(d0 * d0 + d2 * d2);
|
double d3 = Math.sqrt(d0 * d0 + d2 * d2);
|
||||||
this.setXRot(Mth.clamp(Mth.wrapDegrees((float) (-(Mth.atan2(d1, d3) * 57.2957763671875))), -90, 40));
|
|
||||||
float targetY = Mth.wrapDegrees((float) (Mth.atan2(d2, d0) * 57.2957763671875) - 90.0F);
|
|
||||||
|
|
||||||
|
float targetY = Mth.wrapDegrees((float) (Mth.atan2(d2, d0) * 57.2957763671875) - 90.0F);
|
||||||
float diffY = Math.clamp(-90f, 90f, Mth.wrapDegrees(targetY - this.getYRot()));
|
float diffY = Math.clamp(-90f, 90f, Mth.wrapDegrees(targetY - this.getYRot()));
|
||||||
|
|
||||||
turretTurnSound(0, diffY, 1.1f);
|
turretTurnSound(0, diffY, 1.1f);
|
||||||
|
|
||||||
|
this.setXRot(Mth.clamp(Mth.wrapDegrees((float) (-(Mth.atan2(d1, d3) * 57.2957763671875))), -90, 40));
|
||||||
this.setYRot(this.getYRot() + Mth.clamp(0.9f * diffY, -20f, 20f));
|
this.setYRot(this.getYRot() + Mth.clamp(0.9f * diffY, -20f, 20f));
|
||||||
|
|
||||||
if (target.distanceTo(this) <= 144 && VectorTool.calculateAngle(getViewVector(1), targetVec) < 10) {
|
if (target.distanceTo(this) <= 144 && VectorTool.calculateAngle(getViewVector(1), targetVec) < 10) {
|
||||||
|
@ -473,10 +476,10 @@ public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEnti
|
||||||
var entityToSpawn = ((SmallCannonShellWeapon) getWeapon(0)).create(player);
|
var entityToSpawn = ((SmallCannonShellWeapon) getWeapon(0)).create(player);
|
||||||
|
|
||||||
Matrix4f transform = getBarrelTransform(1);
|
Matrix4f transform = getBarrelTransform(1);
|
||||||
Vector4f worldPosition = transformPosition(transform, 0f, 0.4f, 2.6875f);
|
Vector4f worldPosition = transformPosition(transform, 0f, 0.4f, 0);
|
||||||
|
|
||||||
entityToSpawn.setPos(worldPosition.x, worldPosition.y, worldPosition.z);
|
entityToSpawn.setPos(worldPosition.x, worldPosition.y, worldPosition.z);
|
||||||
entityToSpawn.shoot(getLookAngle().x, getLookAngle().y + 0.001, getLookAngle().z, 30, 0.75f);
|
entityToSpawn.shoot(getLookAngle().x, getLookAngle().y, getLookAngle().z, 30, 0.75f);
|
||||||
level().addFreshEntity(entityToSpawn);
|
level().addFreshEntity(entityToSpawn);
|
||||||
|
|
||||||
this.entityData.set(GUN_ROTATE, entityData.get(GUN_ROTATE) + 0.5f);
|
this.entityData.set(GUN_ROTATE, entityData.get(GUN_ROTATE) + 0.5f);
|
||||||
|
|
|
@ -69,5 +69,84 @@ public class RangeTool {
|
||||||
}
|
}
|
||||||
return validT;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue