优化投弹
This commit is contained in:
parent
81a91f0a84
commit
58a88578ad
6 changed files with 241 additions and 11 deletions
|
@ -35,6 +35,7 @@ import java.util.List;
|
|||
|
||||
import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit;
|
||||
import static com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity.HEAT;
|
||||
import static com.atsuishio.superbwarfare.event.ClientEventHandler.zoomVehicle;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class AircraftOverlay implements LayeredDraw.Layer {
|
||||
|
@ -45,6 +46,8 @@ public class AircraftOverlay implements LayeredDraw.Layer {
|
|||
private static float lerpLock = 1;
|
||||
private static float lerpG = 1;
|
||||
|
||||
private static float scopeScale = 1;
|
||||
|
||||
private static final ResourceLocation FRAME = Mod.loc("textures/screens/aircraft/frame.png");
|
||||
private static final ResourceLocation FRAME_TARGET = Mod.loc("textures/screens/aircraft/frame_target.png");
|
||||
private static final ResourceLocation FRAME_LOCK = Mod.loc("textures/screens/aircraft/frame_lock.png");
|
||||
|
@ -60,7 +63,6 @@ public class AircraftOverlay implements LayeredDraw.Layer {
|
|||
Camera camera = mc.gameRenderer.getMainCamera();
|
||||
Vec3 cameraPos = camera.getPosition();
|
||||
PoseStack poseStack = guiGraphics.pose();
|
||||
Vec3 lookVec = new Vec3(camera.getLookVector());
|
||||
|
||||
var partialTick = deltaTracker.getGameTimeDeltaPartialTick(true);
|
||||
|
||||
|
@ -89,6 +91,42 @@ public class AircraftOverlay implements LayeredDraw.Layer {
|
|||
Vec3 p = VectorUtil.worldToScreen(pos, cameraPos);
|
||||
Vec3 pCross = VectorUtil.worldToScreen(posCross, cameraPos);
|
||||
|
||||
// 投弹准星
|
||||
if (mobileVehicle instanceof A10Entity a10Entity && weaponVehicle.getWeaponIndex(0) == 2 && (zoomVehicle || mc.options.getCameraType() != CameraType.FIRST_PERSON)) {
|
||||
Vec3 p0 = a10Entity.bombLandingPosO;
|
||||
Vec3 p1 = a10Entity.bombLandingPos;
|
||||
if (p0 != null && p1 != null) {
|
||||
Vec3 bombCross = p0.lerp(p1, partialTick);
|
||||
pCross = VectorUtil.worldToScreen(bombCross, cameraPos);
|
||||
|
||||
if (pCross != null && zoomVehicle) {
|
||||
float f = (float) Math.min(screenWidth, screenHeight);
|
||||
float f1 = Math.min((float) screenWidth / f, (float) screenHeight / f);
|
||||
int i = Mth.floor(f * f1);
|
||||
int j = Mth.floor(f * f1);
|
||||
|
||||
float x = (float) pCross.x;
|
||||
float y = (float) pCross.y;
|
||||
poseStack.pushPose();
|
||||
poseStack.rotateAround(Axis.ZP.rotationDegrees(aircraftEntity.getRotZ(partialTick)), x, y, 0);
|
||||
poseStack.pushPose();
|
||||
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(x, y, 0);
|
||||
guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("MK82 BOMB " + aircraftEntity.getAmmoCount(player)), 25, -11, 1, false);
|
||||
poseStack.popPose();
|
||||
|
||||
preciseBlit(guiGraphics, Mod.loc("textures/screens/aircraft/bomb_scope.png"), x - 1.5f * i, y - 1.5f * j, 0, 0, 3 * i, 3 * j, 3 * i, 3 * j);
|
||||
preciseBlit(guiGraphics, Mod.loc("textures/screens/aircraft/bomb_scope_pitch.png"), x - 1.5f * i, y - 1.5f * j - 4 * a10Entity.getPitch(partialTick), 0, 0, 3 * i, 3 * j, 3 * i, 3 * j);
|
||||
renderKillIndicator(guiGraphics, x - 7.5f + (float) (2 * (Math.random() - 0.5f)), y - 7.5f + (float) (2 * (Math.random() - 0.5f)));
|
||||
poseStack.popPose();
|
||||
poseStack.popPose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (p != null) {
|
||||
poseStack.pushPose();
|
||||
float x = (float) p.x;
|
||||
|
@ -226,14 +264,13 @@ public class AircraftOverlay implements LayeredDraw.Layer {
|
|||
} else if (mc.options.getCameraType() == CameraType.THIRD_PERSON_BACK) {
|
||||
poseStack.pushPose();
|
||||
poseStack.rotateAround(Axis.ZP.rotationDegrees(aircraftEntity.getRotZ(partialTick)), x, y, 0);
|
||||
preciseBlit(guiGraphics, Mod.loc("textures/screens/drone.png"), x - 8, y - 8, 0, 0, 16, 16, 16, 16);
|
||||
renderKillIndicator(guiGraphics, x - 7.5f + (float) (2 * (Math.random() - 0.5f)), y - 7.5f + (float) (2 * (Math.random() - 0.5f)));
|
||||
|
||||
poseStack.pushPose();
|
||||
|
||||
poseStack.translate(x, y, 0);
|
||||
poseStack.scale(0.75f, 0.75f, 1);
|
||||
|
||||
ResourceLocation cross = Mod.loc("textures/screens/drone.png");
|
||||
float size = 16;
|
||||
|
||||
if (mobileVehicle instanceof A10Entity a10Entity) {
|
||||
if (weaponVehicle.getWeaponIndex(0) == 0) {
|
||||
double heat = a10Entity.getEntityData().get(HEAT) / 100.0F;
|
||||
|
@ -241,6 +278,8 @@ public class AircraftOverlay implements LayeredDraw.Layer {
|
|||
} else if (weaponVehicle.getWeaponIndex(0) == 1) {
|
||||
guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("70MM ROCKET " + aircraftEntity.getAmmoCount(player)), 25, -9, -1, false);
|
||||
} else if (weaponVehicle.getWeaponIndex(0) == 2) {
|
||||
cross = Mod.loc("textures/screens/shotgun_hud.png");
|
||||
size = 24;
|
||||
guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("MK82 BOMB " + aircraftEntity.getAmmoCount(player)), 25, -9, -1, false);
|
||||
} else if (weaponVehicle.getWeaponIndex(0) == 3) {
|
||||
guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("AGM-65 " + aircraftEntity.getAmmoCount(player)), 25, -9, -1, false);
|
||||
|
@ -249,6 +288,8 @@ public class AircraftOverlay implements LayeredDraw.Layer {
|
|||
|
||||
guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("IR FLARES " + aircraftEntity.getDecoy()), 25, 1, -1, false);
|
||||
poseStack.popPose();
|
||||
preciseBlit(guiGraphics, cross, x - 0.5f * size, y - 0.5f * size, 0, 0, size, size, size, size);
|
||||
renderKillIndicator(guiGraphics, x - 7.5f + (float) (2 * (Math.random() - 0.5f)), y - 7.5f + (float) (2 * (Math.random() - 0.5f)));
|
||||
poseStack.popPose();
|
||||
}
|
||||
poseStack.popPose();
|
||||
|
|
|
@ -2,14 +2,17 @@ package com.atsuishio.superbwarfare.client.renderer.entity;
|
|||
|
||||
import com.atsuishio.superbwarfare.client.model.entity.A10Model;
|
||||
import com.atsuishio.superbwarfare.entity.vehicle.A10Entity;
|
||||
import com.atsuishio.superbwarfare.event.ClientEventHandler;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.math.Axis;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import software.bernie.geckolib.cache.object.BakedGeoModel;
|
||||
|
@ -54,6 +57,10 @@ public class A10Renderer extends GeoEntityRenderer<A10Entity> {
|
|||
@Override
|
||||
public void renderRecursively(PoseStack poseStack, A10Entity animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) {
|
||||
String name = bone.getName();
|
||||
if (name.equals("root")) {
|
||||
Player player = Minecraft.getInstance().player;
|
||||
bone.setHidden(ClientEventHandler.zoomVehicle && animatable.getFirstPassenger() == player && animatable.getWeaponIndex(0) == 2);
|
||||
}
|
||||
if (name.equals("wingLR")) {
|
||||
bone.setRotX(1.5f * Mth.lerp(partialTick, animatable.flap1LRotO, animatable.getFlap1LRot()) * Mth.DEG_TO_RAD);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import com.atsuishio.superbwarfare.entity.OBBEntity;
|
|||
import com.atsuishio.superbwarfare.entity.vehicle.base.*;
|
||||
import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier;
|
||||
import com.atsuishio.superbwarfare.entity.vehicle.weapon.*;
|
||||
import com.atsuishio.superbwarfare.event.ClientEventHandler;
|
||||
import com.atsuishio.superbwarfare.event.ClientMouseHandler;
|
||||
import com.atsuishio.superbwarfare.init.ModDamageTypes;
|
||||
import com.atsuishio.superbwarfare.init.ModItems;
|
||||
|
@ -17,6 +16,8 @@ import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage;
|
|||
import com.atsuishio.superbwarfare.tools.*;
|
||||
import com.mojang.math.Axis;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
|
@ -58,6 +59,7 @@ import software.bernie.geckolib.util.GeckoLibUtil;
|
|||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static com.atsuishio.superbwarfare.event.ClientEventHandler.zoomVehicle;
|
||||
import static com.atsuishio.superbwarfare.event.ClientMouseHandler.freeCameraPitch;
|
||||
import static com.atsuishio.superbwarfare.event.ClientMouseHandler.freeCameraYaw;
|
||||
import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle;
|
||||
|
@ -84,6 +86,10 @@ public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity
|
|||
private boolean wasFiring = false;
|
||||
public float delta_x;
|
||||
public float delta_y;
|
||||
public Vec3 bombLandingPosO;
|
||||
public Vec3 bombLandingPos;
|
||||
public Vec3 deltaMovementO;
|
||||
|
||||
public OBB obb;
|
||||
public OBB obb2;
|
||||
public OBB obb3;
|
||||
|
@ -222,6 +228,8 @@ public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity
|
|||
this.wasFiring = this.isFiring();
|
||||
|
||||
this.lockingTargetO = getTargetUuid();
|
||||
bombLandingPosO = bombLandingPos;
|
||||
deltaMovementO = getDeltaMovement();
|
||||
|
||||
super.baseTick();
|
||||
this.updateOBB();
|
||||
|
@ -277,6 +285,12 @@ public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity
|
|||
lowHealthWarning();
|
||||
|
||||
releaseDecoy();
|
||||
|
||||
// 计算航弹落点
|
||||
if (level().isClientSide) {
|
||||
bombLandingPos = ProjectileCalculator.calculateImpactPosition(level(), shootPos(1), shootVec(1), -0.06).getCenter();
|
||||
}
|
||||
|
||||
this.refreshDimensions();
|
||||
}
|
||||
|
||||
|
@ -734,8 +748,10 @@ public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity
|
|||
worldPosition = transformPosition(transform, 0.1321625f, -0.56446875f, 7.85210625f);
|
||||
} else if (getWeaponIndex(0) == 1) {
|
||||
worldPosition = transformPosition(transform, 0f, -1.443f, 0.13f);
|
||||
} else {
|
||||
} else if (getWeaponIndex(0) == 2) {
|
||||
worldPosition = transformPosition(transform, 0f, -1.203125f, 0.0625f);
|
||||
} else {
|
||||
worldPosition = transformPosition(transform, 0, -1.55f, 1.83f);
|
||||
}
|
||||
return new Vec3(worldPosition.x, worldPosition.y, worldPosition.z);
|
||||
}
|
||||
|
@ -745,7 +761,9 @@ public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity
|
|||
Matrix4f transform = getVehicleTransform(tickDelta);
|
||||
Vector4f worldPosition;
|
||||
Vector4f worldPosition2;
|
||||
if (getWeaponIndex(0) == 3) {
|
||||
if (getWeaponIndex(0) == 2) {
|
||||
return deltaMovementO.lerp(getDeltaMovement(), tickDelta).scale(0.75);
|
||||
} else if (getWeaponIndex(0) == 3) {
|
||||
worldPosition = transformPosition(transform, 0, 0, 0);
|
||||
worldPosition2 = transformPosition(transform, 0, 0f, 1);
|
||||
} else {
|
||||
|
@ -849,7 +867,7 @@ public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity
|
|||
}
|
||||
|
||||
Mk82Entity.setPos(worldPosition.x, worldPosition.y, worldPosition.z);
|
||||
Mk82Entity.shoot(getDeltaMovement().x, getDeltaMovement().y, getDeltaMovement().z, (float) getDeltaMovement().length(), 10);
|
||||
Mk82Entity.shoot(getDeltaMovement().x, getDeltaMovement().y, getDeltaMovement().z, (float) getDeltaMovement().scale(0.75).length(), 0.5f);
|
||||
player.level().addFreshEntity(Mk82Entity);
|
||||
|
||||
BlockPos pos = BlockPos.containing(new Vec3(worldPosition.x, worldPosition.y, worldPosition.z));
|
||||
|
@ -982,7 +1000,7 @@ public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity
|
|||
|
||||
@Override
|
||||
public double getMouseSensitivity() {
|
||||
return ClientEventHandler.zoomVehicle ? 0.03 : 0.07;
|
||||
return zoomVehicle ? 0.03 : 0.07;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1018,7 +1036,21 @@ public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity
|
|||
@OnlyIn(Dist.CLIENT)
|
||||
@Override
|
||||
public @Nullable Vec2 getCameraRotation(float partialTicks, Player player, boolean zoom, boolean isFirstPerson) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
Camera camera = mc.gameRenderer.getMainCamera();
|
||||
Vec3 cameraPos = camera.getPosition();
|
||||
|
||||
Vec3 p0 = bombLandingPosO;
|
||||
Vec3 p1 = bombLandingPos;
|
||||
Vec3 p2 = getViewVector(partialTicks);
|
||||
if (p0 != null && p1 != null) {
|
||||
p2 = cameraPos.vectorTo(p0.lerp(p1, partialTicks));
|
||||
}
|
||||
|
||||
if (this.getSeatIndex(player) == 0) {
|
||||
if (getWeaponIndex(0) == 2 && zoomVehicle) {
|
||||
return new Vec2((float) (-getYRotFromVector(p2) - freeCameraYaw), (float) (-getXRotFromVector(p2) + freeCameraPitch));
|
||||
}
|
||||
return new Vec2((float) (getRotY(partialTicks) - freeCameraYaw), (float) (getRotX(partialTicks) + freeCameraPitch));
|
||||
}
|
||||
|
||||
|
@ -1029,8 +1061,12 @@ public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity
|
|||
@Override
|
||||
public Vec3 getCameraPosition(float partialTicks, Player player, boolean zoom, boolean isFirstPerson) {
|
||||
if (this.getSeatIndex(player) == 0) {
|
||||
Matrix4f transform = getClientVehicleTransform(partialTicks);
|
||||
|
||||
if (getWeaponIndex(0) == 2 && zoomVehicle) {
|
||||
return shootPos(partialTicks);
|
||||
}
|
||||
|
||||
Matrix4f transform = getClientVehicleTransform(partialTicks);
|
||||
Vector4f maxCameraPosition = transformPosition(transform, 0, 4, -14 - (float) ClientMouseHandler.custom3pDistanceLerp);
|
||||
Vec3 finalPos = CameraTool.getMaxZoom(transform, maxCameraPosition);
|
||||
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
package com.atsuishio.superbwarfare.tools;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class ProjectileCalculator {
|
||||
private static final double TIME_STEP = 0.1; // 时间步长(刻)
|
||||
private static final int MAX_ITERATIONS = 1000; // 最大迭代次数
|
||||
|
||||
/**
|
||||
* 计算炮弹落地位置
|
||||
*
|
||||
* @param world 世界对象
|
||||
* @param startPos 发射点位置
|
||||
* @param launchVector 发射向量
|
||||
* @return 预测的落点方块位置
|
||||
*/
|
||||
public static BlockPos calculateImpactPosition(Level world, Vec3 startPos, Vec3 launchVector, double gravity) {
|
||||
// 当前炮弹位置和速度
|
||||
Vec3 currentPos = startPos;
|
||||
Vec3 currentVelocity = launchVector;
|
||||
|
||||
// 记录上一刻位置
|
||||
Vec3 prevPos = startPos;
|
||||
|
||||
for (int i = 0; i < MAX_ITERATIONS; i++) {
|
||||
// 更新位置
|
||||
Vec3 nextPos = currentPos.add(
|
||||
currentVelocity.x * TIME_STEP,
|
||||
currentVelocity.y * TIME_STEP,
|
||||
currentVelocity.z * TIME_STEP
|
||||
);
|
||||
|
||||
// 更新速度(重力影响)
|
||||
currentVelocity = currentVelocity.add(0, gravity * TIME_STEP, 0);
|
||||
|
||||
// 检查是否碰撞方块
|
||||
BlockPos collisionPos = checkCollision(world, prevPos, nextPos);
|
||||
if (collisionPos != null) {
|
||||
return collisionPos;
|
||||
}
|
||||
|
||||
// 更新位置进行下一步
|
||||
prevPos = currentPos;
|
||||
currentPos = nextPos;
|
||||
|
||||
// 安全检查:防止飞出世界边界
|
||||
if (currentPos.y < world.getMinBuildHeight() || currentPos.y > world.getMaxBuildHeight()) {
|
||||
return new BlockPos(
|
||||
(int)Math.floor(currentPos.x),
|
||||
(int)Math.floor(currentPos.y),
|
||||
(int)Math.floor(currentPos.z)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 超过最大迭代次数,返回当前位置
|
||||
return new BlockPos(
|
||||
(int)Math.floor(currentPos.x),
|
||||
(int)Math.floor(currentPos.y),
|
||||
(int)Math.floor(currentPos.z)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查两点之间是否有碰撞方块
|
||||
*/
|
||||
private static BlockPos checkCollision(Level world, Vec3 start, Vec3 end) {
|
||||
// 使用距离和方向向量
|
||||
double dx = end.x - start.x;
|
||||
double dy = end.y - start.y;
|
||||
double dz = end.z - start.z;
|
||||
double distance = Math.sqrt(dx*dx + dy*dy + dz*dz);
|
||||
|
||||
if (distance == 0) return null;
|
||||
|
||||
// 方向单位向量
|
||||
double dirX = dx / distance;
|
||||
double dirY = dy / distance;
|
||||
double dirZ = dz / distance;
|
||||
|
||||
// 步进检查
|
||||
double stepSize = 0.1; // 检查步长
|
||||
for (double t = 0; t < distance; t += stepSize) {
|
||||
double x = start.x + dirX * t;
|
||||
double y = start.y + dirY * t;
|
||||
double z = start.z + dirZ * t;
|
||||
|
||||
BlockPos pos = new BlockPos((int)Math.floor(x), (int)Math.floor(y), (int)Math.floor(z));
|
||||
BlockState state = world.getBlockState(pos);
|
||||
|
||||
// 检查是否碰到固体方块
|
||||
if (!state.isAir()) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
// 检查是否碰到下方方块(炮弹落地)
|
||||
BlockPos belowPos = pos.below();
|
||||
BlockState belowState = world.getBlockState(belowPos);
|
||||
|
||||
if (y - Math.floor(y) < 0.1 && !belowState.isAir()) {
|
||||
return belowPos;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 快速预测落点(不考虑地形,仅数学计算)
|
||||
* 用于平坦地形或初始估算
|
||||
*/
|
||||
public static Vec3 estimateLandingPosition(Vec3 startPos, Vec3 launchVector, double gravity) {
|
||||
double vx = launchVector.x;
|
||||
double vy = launchVector.y;
|
||||
double vz = launchVector.z;
|
||||
|
||||
// 计算飞行时间 (解二次方程: y = y0 + vy*t + 0.5*g*t² = 0)
|
||||
double a = 0.5 * gravity;
|
||||
double b = vy;
|
||||
double c = startPos.y; // 假设地面高度为0
|
||||
|
||||
// 计算判别式
|
||||
double discriminant = b*b - 4*a*c;
|
||||
|
||||
if (discriminant < 0) {
|
||||
// 无实数解,炮弹不会落地
|
||||
return null;
|
||||
}
|
||||
|
||||
// 取正数解
|
||||
double t = (-b + Math.sqrt(discriminant)) / (2*a);
|
||||
if (t < 0) {
|
||||
t = (-b - Math.sqrt(discriminant)) / (2*a);
|
||||
}
|
||||
|
||||
// 计算落点
|
||||
double x = startPos.x + vx * t;
|
||||
double z = startPos.z + vz * t;
|
||||
|
||||
return new Vec3(x, 0, z);
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Loading…
Add table
Reference in a new issue