提取瞄准方法

This commit is contained in:
17146 2025-05-01 17:56:33 +08:00 committed by Light_Quanta
parent 61bd74c8f4
commit 5f3486eaae
No known key found for this signature in database
GPG key ID: 11A39A1B8C890959
4 changed files with 77 additions and 63 deletions

View file

@ -7,6 +7,7 @@ import com.atsuishio.superbwarfare.entity.TargetEntity;
import com.atsuishio.superbwarfare.entity.projectile.GunGrenadeEntity;
import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity;
import com.atsuishio.superbwarfare.entity.projectile.SmallCannonShellEntity;
import com.atsuishio.superbwarfare.entity.vehicle.base.AutoAimable;
import com.atsuishio.superbwarfare.entity.vehicle.base.CannonEntity;
import com.atsuishio.superbwarfare.entity.vehicle.base.ContainerMobileVehicleEntity;
import com.atsuishio.superbwarfare.entity.vehicle.base.ThirdPersonCameraPosition;
@ -61,7 +62,8 @@ import java.util.stream.StreamSupport;
import static com.atsuishio.superbwarfare.tools.SeekTool.smokeFilter;
public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEntity, CannonEntity, OwnableEntity {
public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEntity, CannonEntity, OwnableEntity, AutoAimable {
public static final EntityDataAccessor<Integer> ANIM_TIME = SynchedEntityData.defineId(Hpj11Entity.class, EntityDataSerializers.INT);
public static final EntityDataAccessor<Float> GUN_ROTATE = SynchedEntityData.defineId(Hpj11Entity.class, EntityDataSerializers.FLOAT);
public static final EntityDataAccessor<Boolean> ACTIVE = SynchedEntityData.defineId(Hpj11Entity.class, EntityDataSerializers.BOOLEAN);
@ -263,7 +265,7 @@ public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEnti
Vec3 barrelRootPos = new Vec3(worldPosition.x, worldPosition.y, worldPosition.z);
if (entityData.get(TARGET_UUID).equals("none") && tickCount % 2 == 0) {
Entity naerestEntity = seekNearLivingEntity(barrelRootPos, -32.5, 90, 3, 160, 0.3);
Entity naerestEntity = seekNearLivingEntity(this, barrelRootPos, -32.5, 90, 3, 160, 0.3);
if (naerestEntity != null) {
entityData.set(TARGET_UUID, naerestEntity.getStringUUID());
this.consumeEnergy(VehicleConfig.HPJ11_SEEK_COST.get());
@ -314,7 +316,7 @@ public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEnti
this.setYRot(this.getYRot() + Mth.clamp(0.9f * diffY, -20f, 20f));
if (target.distanceTo(this) <= 144 && VectorTool.calculateAngle(getViewVector(1), targetVec) < 10) {
if (checkNoClip(target, barrelRootPos) && entityData.get(AMMO) > 0) {
if (checkNoClip(this, target, barrelRootPos) && entityData.get(AMMO) > 0) {
vehicleShoot(player, 0);
findEntityOnPath(barrelRootPos, targetVec);
} else {
@ -364,7 +366,7 @@ public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEnti
Entity target = StreamSupport.stream(EntityFindUtil.getEntities(level()).getAll().spliterator(), false)
.filter(e -> {
if (e == entity && e instanceof Projectile && !(e instanceof ProjectileEntity || e instanceof SmallCannonShellEntity)) {
return checkNoClip(e, pos);
return checkNoClip(this, e, pos);
}
return false;
}).min(Comparator.comparingDouble(e -> e.distanceTo(this))).orElse(null);

View file

@ -2,6 +2,7 @@ package com.atsuishio.superbwarfare.entity.vehicle;
import com.atsuishio.superbwarfare.config.server.VehicleConfig;
import com.atsuishio.superbwarfare.entity.TargetEntity;
import com.atsuishio.superbwarfare.entity.vehicle.base.AutoAimable;
import com.atsuishio.superbwarfare.entity.vehicle.base.EnergyVehicleEntity;
import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier;
import com.atsuishio.superbwarfare.init.*;
@ -47,7 +48,7 @@ import java.util.UUID;
import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle;
import static com.atsuishio.superbwarfare.tools.SeekTool.smokeFilter;
public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity, OwnableEntity {
public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity, OwnableEntity, AutoAimable {
public static final EntityDataAccessor<Integer> COOL_DOWN = SynchedEntityData.defineId(LaserTowerEntity.class, EntityDataSerializers.INT);
public static final EntityDataAccessor<String> TARGET_UUID = SynchedEntityData.defineId(LaserTowerEntity.class, EntityDataSerializers.STRING);
@ -241,7 +242,7 @@ public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity,
Vec3 barrelRootPos = new Vec3(this.getX(), this.getY() + 1.390625f, this.getZ());
if (entityData.get(TARGET_UUID).equals("none") && tickCount % 5 == 0) {
Entity naerestEntity = seekNearLivingEntity(barrelRootPos,-40, 90,1,72, 0.01);
Entity naerestEntity = seekNearLivingEntity(this, barrelRootPos, -40, 90, 1, 72, 0.01);
if (naerestEntity != null) {
entityData.set(TARGET_UUID, naerestEntity.getStringUUID());
}
@ -291,7 +292,7 @@ public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity,
changeTargetTimer++;
}
if (this.entityData.get(COOL_DOWN) == 0 && VectorTool.calculateAngle(getViewVector(1), targetVec) < 1 && checkNoClip(target, barrelRootPos)) {
if (this.entityData.get(COOL_DOWN) == 0 && VectorTool.calculateAngle(getViewVector(1), targetVec) < 1 && checkNoClip(this, target, barrelRootPos)) {
this.entityData.set(COOL_DOWN, VehicleConfig.LASER_TOWER_COOLDOWN.get());
if (level() instanceof ServerLevel serverLevel) {

View file

@ -0,0 +1,66 @@
package com.atsuishio.superbwarfare.entity.vehicle.base;
import com.atsuishio.superbwarfare.tools.EntityFindUtil;
import com.atsuishio.superbwarfare.tools.VectorTool;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.monster.Enemy;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import java.util.Comparator;
import java.util.stream.StreamSupport;
import static com.atsuishio.superbwarfare.tools.SeekTool.smokeFilter;
public interface AutoAimable {
// 防御类载具实体搜寻周围实体
default Entity seekNearLivingEntity(Entity attacker, Vec3 pos, double minAngle, double maxAngle, double minRange, double seekRange, double size) {
return StreamSupport.stream(EntityFindUtil.getEntities(attacker.level()).getAll().spliterator(), false)
.filter(e -> {
// TODO 自定义目标列表
if (e.distanceTo(attacker) > minRange
&& e.distanceTo(attacker) <= seekRange
&& canAim(pos, e, minAngle, maxAngle)
&& !(e instanceof Player player && (player.isSpectator() || player.isCreative()))
&& ((e instanceof LivingEntity living && living instanceof Enemy && living.getHealth() > 0) || e == seekThreateningEntity(attacker, size, pos) || basicEnemyFilter(e))
&& smokeFilter(e)) {
return checkNoClip(attacker, e, pos);
}
return false;
}).min(Comparator.comparingDouble(e -> e.distanceTo(attacker))).orElse(null);
}
// 判断具有威胁的弹射物
default Entity seekThreateningEntity(Entity attacker, double size, Vec3 pos) {
return StreamSupport.stream(EntityFindUtil.getEntities(attacker.level()).getAll().spliterator(), false)
.filter(e -> {
if (!e.onGround() && e instanceof Projectile projectile && (e.getBbWidth() >= size || e.getBbHeight() >= size) &&
VectorTool.calculateAngle(e.getDeltaMovement().normalize(), e.position().vectorTo(attacker.position()).normalize()) < 30) {
return checkNoClip(attacker, e, pos) && basicEnemyProjectileFilter(projectile);
}
return false;
}).min(Comparator.comparingDouble(e -> e.distanceTo(attacker))).orElse(null);
}
// 判断载具和目标之间有无障碍物
default boolean checkNoClip(Entity attacker, Entity target, Vec3 pos) {
return attacker.level().clip(new ClipContext(pos, target.getEyePosition(),
ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, attacker)).getType() != HitResult.Type.BLOCK;
}
boolean basicEnemyFilter(Entity pEntity);
boolean basicEnemyProjectileFilter(Projectile projectile);
static boolean canAim(Vec3 pos, Entity target, double minAngle, double maxAngle) {
Vec3 targetPos = new Vec3(target.getX(), target.getY() + target.getBbHeight() / 2, target.getZ());
Vec3 toVec = pos.vectorTo(targetPos).normalize();
double targetAngle = VehicleEntity.getXRotFromVector(toVec);
return minAngle < targetAngle && targetAngle < maxAngle;
}
}

View file

@ -42,19 +42,15 @@ import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.damagesource.DamageTypes;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.monster.Enemy;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.entity.projectile.ThrownPotion;
import net.minecraft.world.entity.vehicle.DismountHelper;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
@ -67,17 +63,15 @@ import org.joml.Matrix4f;
import org.joml.Vector4f;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.StreamSupport;
import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit;
import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle;
import static com.atsuishio.superbwarfare.tools.SeekTool.smokeFilter;
public abstract class VehicleEntity extends Entity {
public static final EntityDataAccessor<Float> HEALTH = SynchedEntityData.defineId(VehicleEntity.class, EntityDataSerializers.FLOAT);
public static final EntityDataAccessor<String> LAST_ATTACKER_UUID = SynchedEntityData.defineId(VehicleEntity.class, EntityDataSerializers.STRING);
public static final EntityDataAccessor<String> LAST_DRIVER_UUID = SynchedEntityData.defineId(VehicleEntity.class, EntityDataSerializers.STRING);
@ -976,55 +970,6 @@ public abstract class VehicleEntity extends Entity {
return getEyePosition();
}
//防御类载具实体搜寻周围实体
public Entity seekNearLivingEntity(Vec3 pos, double minAngle, double maxAngle, double minRange, double seekRange, double size) {
return StreamSupport.stream(EntityFindUtil.getEntities(level()).getAll().spliterator(), false)
.filter(e -> {
// TODO 自定义目标列表
if (e.distanceTo(this) > minRange
&& e.distanceTo(this) <= seekRange
&& canAim(pos, e, minAngle, maxAngle)
&& !(e instanceof Player player && (player.isSpectator() || player.isCreative()))
&& ((e instanceof LivingEntity living && living instanceof Enemy && living.getHealth() > 0) || e == seekThreateningEntity(size, pos) || basicEnemyFilter(e))
&& smokeFilter(e)) {
return checkNoClip(e, pos);
}
return false;
}).min(Comparator.comparingDouble(e -> e.distanceTo(this))).orElse(null);
}
//判断具有威胁的弹射物
public Entity seekThreateningEntity(double size, Vec3 pos) {
return StreamSupport.stream(EntityFindUtil.getEntities(level()).getAll().spliterator(), false)
.filter(e -> {
if (!e.onGround() && e instanceof Projectile projectile && (e.getBbWidth() >= size || e.getBbHeight() >= size) && VectorTool.calculateAngle(e.getDeltaMovement().normalize(), e.position().vectorTo(this.position()).normalize()) < 30) {
return checkNoClip(e, pos) && basicEnemyProjectileFilter(projectile);
}
return false;
}).min(Comparator.comparingDouble(e -> e.distanceTo(this))).orElse(null);
}
//判断载具和目标之间有无障碍物
public boolean checkNoClip(Entity target, Vec3 pos) {
return level().clip(new ClipContext(pos, target.getEyePosition(),
ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)).getType() != HitResult.Type.BLOCK;
}
public boolean basicEnemyFilter(Entity pEntity) {
return false;
}
public boolean basicEnemyProjectileFilter(Projectile projectile) {
return false;
}
public static boolean canAim(Vec3 pos, Entity target, double minAngle, double maxAngle) {
Vec3 targetPos = new Vec3(target.getX(), target.getY() + target.getBbHeight() / 2, target.getZ());
Vec3 toVec = pos.vectorTo(targetPos).normalize();
double targetAngle = VehicleEntity.getXRotFromVector(toVec);
return minAngle < targetAngle && targetAngle < maxAngle;
}
@OnlyIn(Dist.CLIENT)
public void renderFirstPersonOverlay(GuiGraphics guiGraphics, Font font, Player player, int screenWidth, int screenHeight, float scale) {
if (!(this instanceof WeaponVehicleEntity weaponVehicle)) return;