激光防御塔添加拦截弹射物功能

This commit is contained in:
Atsuishio 2025-04-30 12:23:54 +08:00 committed by Light_Quanta
parent d0043785da
commit 9c071e4767
No known key found for this signature in database
GPG key ID: 11A39A1B8C890959
3 changed files with 78 additions and 65 deletions

View file

@ -35,15 +35,12 @@ import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageTypes; import net.minecraft.world.damagesource.DamageTypes;
import net.minecraft.world.entity.*; import net.minecraft.world.entity.*;
import net.minecraft.world.entity.monster.Enemy;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Explosion; import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.event.EventHooks; import net.neoforged.neoforge.event.EventHooks;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -258,7 +255,7 @@ public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEnti
Vec3 barrelRootPos = new Vec3(worldPosition.x, worldPosition.y, worldPosition.z); Vec3 barrelRootPos = new Vec3(worldPosition.x, worldPosition.y, worldPosition.z);
if (entityData.get(TARGET_UUID).equals("none") && tickCount % 2 == 0) { if (entityData.get(TARGET_UUID).equals("none") && tickCount % 2 == 0) {
Entity naerestEntity = seekNearLivingEntity(barrelRootPos,-32.5,90,3,160); Entity naerestEntity = seekNearLivingEntity(barrelRootPos,-32.5,90,3,160, 0.3);
if (naerestEntity != null) { if (naerestEntity != null) {
entityData.set(TARGET_UUID, naerestEntity.getStringUUID()); entityData.set(TARGET_UUID, naerestEntity.getStringUUID());
} }
@ -300,7 +297,7 @@ public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEnti
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) {
if (checkNoClip(target) && entityData.get(AMMO) > 0) { if (checkNoClip(target, barrelRootPos) && entityData.get(AMMO) > 0) {
vehicleShoot(player, 0); vehicleShoot(player, 0);
findEntityOnPath(barrelRootPos, targetVec); findEntityOnPath(barrelRootPos, targetVec);
@ -335,7 +332,7 @@ public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEnti
Entity target = StreamSupport.stream(EntityFindUtil.getEntities(level()).getAll().spliterator(), false) Entity target = StreamSupport.stream(EntityFindUtil.getEntities(level()).getAll().spliterator(), false)
.filter(e -> { .filter(e -> {
if (e == entity && e instanceof Projectile && !(e instanceof ProjectileEntity || e instanceof SmallCannonShellEntity)) { if (e == entity && e instanceof Projectile && !(e instanceof ProjectileEntity || e instanceof SmallCannonShellEntity)) {
return checkNoClip(e); return checkNoClip(e, pos);
} }
return false; return false;
}).min(Comparator.comparingDouble(e -> e.distanceTo(this))).orElse(null); }).min(Comparator.comparingDouble(e -> e.distanceTo(this))).orElse(null);
@ -365,36 +362,6 @@ public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEnti
ParticleTool.spawnMediumExplosionParticles(this.level(), vec3); ParticleTool.spawnMediumExplosionParticles(this.level(), vec3);
} }
public Entity seekNearLivingEntity(Vec3 pos, double minAngle, double maxAngle, double minRange, double seekRange) {
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 LivingEntity living && living instanceof Enemy && living.getHealth() > 0) || e == seekThreateningEntity())
&& smokeFilter(e)) {
return checkNoClip(e);
}
return false;
}).min(Comparator.comparingDouble(e -> e.distanceTo(this))).orElse(null);
}
public Entity seekThreateningEntity() {
return StreamSupport.stream(EntityFindUtil.getEntities(level()).getAll().spliterator(), false)
.filter(e -> {
if (!e.onGround() && e instanceof Projectile && (e.getBbWidth() >= 0.3 || e.getBbHeight() >= 0.3) && VectorTool.calculateAngle(e.getDeltaMovement().normalize(), e.position().vectorTo(this.position()).normalize()) < 30) {
return checkNoClip(e);
}
return false;
}).min(Comparator.comparingDouble(e -> e.distanceTo(this))).orElse(null);
}
public boolean checkNoClip(Entity target) {
return level().clip(new ClipContext(this.getEyePosition(), target.getEyePosition(),
ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)).getType() != HitResult.Type.BLOCK;
}
public float getGunRot() { public float getGunRot() {
return this.gunRot; return this.gunRot;
} }

View file

@ -25,13 +25,11 @@ import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageTypes; import net.minecraft.world.damagesource.DamageTypes;
import net.minecraft.world.entity.*; import net.minecraft.world.entity.*;
import net.minecraft.world.entity.monster.Enemy;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Explosion; import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.event.EventHooks; import net.neoforged.neoforge.event.EventHooks;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -43,10 +41,8 @@ import software.bernie.geckolib.animation.AnimationState;
import software.bernie.geckolib.animation.*; import software.bernie.geckolib.animation.*;
import software.bernie.geckolib.util.GeckoLibUtil; import software.bernie.geckolib.util.GeckoLibUtil;
import java.util.Comparator;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.stream.StreamSupport;
import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle; import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle;
import static com.atsuishio.superbwarfare.tools.SeekTool.smokeFilter; import static com.atsuishio.superbwarfare.tools.SeekTool.smokeFilter;
@ -244,8 +240,8 @@ public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity,
Vec3 barrelRootPos = new Vec3(this.getX(), this.getY() + 1.390625f, this.getZ()); Vec3 barrelRootPos = new Vec3(this.getX(), this.getY() + 1.390625f, this.getZ());
if (entityData.get(TARGET_UUID).equals("none") && tickCount % 10 == 0) { if (entityData.get(TARGET_UUID).equals("none") && tickCount % 5 == 0) {
Entity naerestEntity = seekNearLivingEntity(barrelRootPos,-40, 90,1,72); Entity naerestEntity = seekNearLivingEntity(barrelRootPos,-40, 90,1,72, 0.01);
if (naerestEntity != null) { if (naerestEntity != null) {
entityData.set(TARGET_UUID, naerestEntity.getStringUUID()); entityData.set(TARGET_UUID, naerestEntity.getStringUUID());
} }
@ -254,6 +250,10 @@ public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity,
Entity target = EntityFindUtil.findEntity(level(), entityData.get(TARGET_UUID)); Entity target = EntityFindUtil.findEntity(level(), entityData.get(TARGET_UUID));
if (target != null && smokeFilter(target)) { if (target != null && smokeFilter(target)) {
if (target.distanceTo(this) > 72) {
this.entityData.set(TARGET_UUID, "none");
return;
}
if (target instanceof LivingEntity living && living.getHealth() <= 0) { if (target instanceof LivingEntity living && living.getHealth() <= 0) {
this.entityData.set(TARGET_UUID, "none"); this.entityData.set(TARGET_UUID, "none");
return; return;
@ -262,6 +262,10 @@ public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity,
this.entityData.set(TARGET_UUID, "none"); this.entityData.set(TARGET_UUID, "none");
return; return;
} }
if (target instanceof Projectile && (VectorTool.calculateAngle(target.getDeltaMovement().normalize(), target.position().vectorTo(this.position()).normalize()) > 60 || target.onGround())) {
this.entityData.set(TARGET_UUID, "none");
return;
}
Vec3 targetVec = barrelRootPos.vectorTo(target.getEyePosition()).normalize(); Vec3 targetVec = barrelRootPos.vectorTo(target.getEyePosition()).normalize();
@ -283,7 +287,7 @@ public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity,
changeTargetTimer++; changeTargetTimer++;
} }
if (this.entityData.get(COOL_DOWN) == 0 && VectorTool.calculateAngle(getViewVector(1), targetVec) < 1 && checkNoClip(target)) { if (this.entityData.get(COOL_DOWN) == 0 && VectorTool.calculateAngle(getViewVector(1), targetVec) < 1 && checkNoClip(target, barrelRootPos)) {
this.entityData.set(COOL_DOWN, VehicleConfig.LASER_TOWER_COOLDOWN.get()); this.entityData.set(COOL_DOWN, VehicleConfig.LASER_TOWER_COOLDOWN.get());
if (level() instanceof ServerLevel serverLevel) { if (level() instanceof ServerLevel serverLevel) {
@ -298,6 +302,12 @@ public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity,
if (Math.random() < 0.25 && target instanceof LivingEntity living) { if (Math.random() < 0.25 && target instanceof LivingEntity living) {
living.setRemainingFireTicks(2); living.setRemainingFireTicks(2);
} }
if (target instanceof Projectile) {
causeAirExplode(target.position());
target.discard();
}
if (!target.isAlive()) { if (!target.isAlive()) {
entityData.set(TARGET_UUID, "none"); entityData.set(TARGET_UUID, "none");
} }
@ -314,26 +324,22 @@ public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity,
} }
} }
public Entity seekNearLivingEntity(Vec3 pos, double minAngle, double maxAngle, double minRange, double seekRange) { private void causeAirExplode(Vec3 vec3) {
return StreamSupport.stream(EntityFindUtil.getEntities(level()).getAll().spliterator(), false) CustomExplosion explosion = new CustomExplosion(this.level(), this,
.filter(e -> { ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(),
// TODO 自定义目标列表 this,
if (e.distanceTo(this) > minRange this.getOwner()),
&& e.distanceTo(this) <= seekRange 5,
&& canAim(pos, e, minAngle, maxAngle) vec3.x,
&& e instanceof LivingEntity living vec3.y,
&& living instanceof Enemy vec3.z,
&& living.getHealth() > 0 1,
&& smokeFilter(e)) { Explosion.BlockInteraction.KEEP).
return checkNoClip(e); setDamageMultiplier(1);
} explosion.explode();
return false; EventHooks.onExplosionStart(this.level(), explosion);
}).min(Comparator.comparingDouble(e -> e.distanceTo(this))).orElse(null); explosion.finalizeExplosion(false);
} ParticleTool.spawnMediumExplosionParticles(this.level(), vec3);
public boolean checkNoClip(Entity target) {
return level().clip(new ClipContext(this.getEyePosition(), target.getEyePosition(),
ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)).getType() != HitResult.Type.BLOCK;
} }
private PlayState movementPredicate(AnimationState<LaserTowerEntity> event) { private PlayState movementPredicate(AnimationState<LaserTowerEntity> event) {

View file

@ -42,15 +42,19 @@ import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.damagesource.DamageTypes; import net.minecraft.world.damagesource.DamageTypes;
import net.minecraft.world.entity.*; import net.minecraft.world.entity.*;
import net.minecraft.world.entity.monster.Enemy;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.AbstractArrow; 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.projectile.ThrownPotion;
import net.minecraft.world.entity.vehicle.DismountHelper; import net.minecraft.world.entity.vehicle.DismountHelper;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.neoforged.api.distmarker.Dist; import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.api.distmarker.OnlyIn;
@ -63,12 +67,15 @@ import org.joml.Matrix4f;
import org.joml.Vector4f; import org.joml.Vector4f;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.StreamSupport;
import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit; import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit;
import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle; import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle;
import static com.atsuishio.superbwarfare.tools.SeekTool.smokeFilter;
public abstract class VehicleEntity extends Entity { public abstract class VehicleEntity extends Entity {
public static final EntityDataAccessor<Float> HEALTH = SynchedEntityData.defineId(VehicleEntity.class, EntityDataSerializers.FLOAT); public static final EntityDataAccessor<Float> HEALTH = SynchedEntityData.defineId(VehicleEntity.class, EntityDataSerializers.FLOAT);
@ -969,7 +976,40 @@ public abstract class VehicleEntity extends Entity {
return getEyePosition(); return getEyePosition();
} }
public static boolean canAim (Vec3 pos, Entity target, double minAngle, double maxAngle) { //防御类载具实体搜寻周围实体
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 LivingEntity living && living instanceof Enemy && living.getHealth() > 0) || e == seekThreateningEntity(size, pos))
&& 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 && (e.getBbWidth() >= size || e.getBbHeight() >= size) && VectorTool.calculateAngle(e.getDeltaMovement().normalize(), e.position().vectorTo(this.position()).normalize()) < 30) {
return checkNoClip(e, pos);
}
return false;
}).min(Comparator.comparingDouble(e -> e.distanceTo(this))).orElse(null);
}
//判断载具和目标之间有无障碍物
public boolean checkNoClip(Entity target, Vec3 pos) {
return level().clip(new ClipContext(this.getEyePosition(), target.getEyePosition(),
ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)).getType() != HitResult.Type.BLOCK;
}
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 targetPos = new Vec3(target.getX(), target.getY() + target.getBbHeight() / 2, target.getZ());
Vec3 toVec = pos.vectorTo(targetPos).normalize(); Vec3 toVec = pos.vectorTo(targetPos).normalize();
double targetAngle = VehicleEntity.getXRotFromVector(toVec); double targetAngle = VehicleEntity.getXRotFromVector(toVec);