From 7b8ad7c6b5fc8616b51d775cc41d91b03cfa5718 Mon Sep 17 00:00:00 2001 From: Kam Date: Tue, 10 Mar 2026 21:19:49 -0400 Subject: [PATCH] Add Interpolation to Size of Energy Projectiles --- .../client/renderer/RenderEnergyBeam.java | 8 ++++---- .../client/renderer/RenderEnergyDisc.java | 4 ++-- .../client/renderer/RenderEnergyLaser.java | 4 ++-- .../npcs/entity/EntityAbilityBeam.java | 20 ++++++++++++++++++- .../npcs/entity/EntityAbilityDisc.java | 20 +++++++++++++++++++ .../npcs/entity/EntityAbilityLaser.java | 11 ++++++++++ .../npcs/entity/EntityEnergyProjectile.java | 4 ++-- 7 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyBeam.java b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyBeam.java index c870f6a07..17316fcf2 100644 --- a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyBeam.java +++ b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyBeam.java @@ -63,9 +63,9 @@ public class RenderEnergyBeam extends RenderEnergy { double renderOriginY = y - headOffsetY; double renderOriginZ = z - headOffsetZ; - // Get beam properties - float beamWidth = beam.getBeamWidth(); - float headSize = beam.getHeadSize(); + // Get beam properties (interpolated for smooth size transitions) + float beamWidth = beam.getInterpolatedBeamWidth(partialTicks); + float headSize = beam.getInterpolatedHeadSize(partialTicks); int innerColor = beam.getInnerColor(); int outerColor = beam.getOuterColor(); float outerAlpha = beam.getOuterColorAlpha() * proximityAlpha; @@ -105,7 +105,7 @@ public class RenderEnergyBeam extends RenderEnergy { * Grows from 0 to headSize based on charge progress. */ private void renderChargingOrb(EntityAbilityBeam beam, double x, double y, double z, float partialTicks, float proximityAlpha) { - float headSize = beam.getHeadSize(); + float headSize = beam.getInterpolatedHeadSize(partialTicks); float chargeProgress = beam.getInterpolatedChargeProgress(partialTicks); float size = headSize * chargeProgress; diff --git a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyDisc.java b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyDisc.java index eb4d9f21c..93b90023e 100644 --- a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyDisc.java +++ b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyDisc.java @@ -31,8 +31,8 @@ public class RenderEnergyDisc extends RenderEnergy { // Get interpolated values float size = disc.getInterpolatedSize(partialTicks); - float radius = disc.getDiscRadius() * size; - float thickness = disc.getDiscThickness() * size; + float radius = disc.getInterpolatedDiscRadius(partialTicks) * size; + float thickness = disc.getInterpolatedDiscThickness(partialTicks) * size; // Subtle pulsing effect float pulseTime = entity.ticksExisted + partialTicks; diff --git a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyLaser.java b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyLaser.java index c2cfe716a..8b0c79b65 100644 --- a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyLaser.java +++ b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyLaser.java @@ -43,7 +43,7 @@ public class RenderEnergyLaser extends RenderEnergy { double endX = laser.getInterpolatedEndX(partialTicks); double endY = laser.getInterpolatedEndY(partialTicks); double endZ = laser.getInterpolatedEndZ(partialTicks); - float width = laser.getLaserWidth(); + float width = laser.getInterpolatedLaserWidth(partialTicks); float alpha = 1.0f; // Calculate render offset (entity position is used as reference) @@ -156,7 +156,7 @@ public class RenderEnergyLaser extends RenderEnergy { } private void renderChargingOrb(EntityAbilityLaser laser, double x, double y, double z, float partialTicks, float proximityAlpha) { - float headSize = laser.getLaserWidth() * 0.5f; + float headSize = laser.getInterpolatedLaserWidth(partialTicks) * 0.5f; float chargeProgress = laser.getInterpolatedChargeProgress(partialTicks); float size = headSize * chargeProgress; diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java index baeb7f81c..4e5e2e3cb 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java @@ -41,6 +41,8 @@ public class EntityAbilityBeam extends EntityEnergyProjectile { // Beam shape properties private float beamWidth = 0.3f; private float headSize = 0.5f; + private float prevBeamWidth = 0.3f; + private float prevHeadSize = 0.5f; // Trail - list of points showing beam path (RELATIVE to origin!) private List trailPoints = new ArrayList<>(); @@ -240,10 +242,12 @@ public class EntityAbilityBeam extends EntityEnergyProjectile { return; } - // Store previous head offset for interpolation + // Store previous values for interpolation prevHeadOffsetX = headOffsetX; prevHeadOffsetY = headOffsetY; prevHeadOffsetZ = headOffsetZ; + prevBeamWidth = beamWidth; + prevHeadSize = headSize; // Age trail points for fading effect if (isFadingMode()) { @@ -580,7 +584,12 @@ public class EntityAbilityBeam extends EntityEnergyProjectile { return beamWidth; } + public float getInterpolatedBeamWidth(float partialTicks) { + return prevBeamWidth + (beamWidth - prevBeamWidth) * partialTicks; + } + public void setBeamWidth(float beamWidth) { + this.prevBeamWidth = this.beamWidth; this.beamWidth = beamWidth; } @@ -588,7 +597,12 @@ public class EntityAbilityBeam extends EntityEnergyProjectile { return headSize; } + public float getInterpolatedHeadSize(float partialTicks) { + return prevHeadSize + (headSize - prevHeadSize) * partialTicks; + } + public void setHeadSize(float headSize) { + this.prevHeadSize = this.headSize; this.headSize = headSize; } @@ -747,6 +761,8 @@ public class EntityAbilityBeam extends EntityEnergyProjectile { @Override protected void applyProjectileClientSyncData(NBTTagCompound nbt) { + prevBeamWidth = beamWidth; + prevHeadSize = headSize; beamWidth = nbt.getFloat("BeamWidth"); headSize = nbt.getFloat("HeadSize"); setAttachedToOwner(nbt.getBoolean("AttachedToOwner")); @@ -758,6 +774,8 @@ public class EntityAbilityBeam extends EntityEnergyProjectile { protected void readProjectileNBT(NBTTagCompound nbt) { this.beamWidth = sanitize(nbt.hasKey("BeamWidth") ? nbt.getFloat("BeamWidth") : 0.3f, 0.3f, MAX_ENTITY_SIZE); this.headSize = sanitize(nbt.hasKey("HeadSize") ? nbt.getFloat("HeadSize") : 0.5f, 0.5f, MAX_ENTITY_SIZE); + this.prevBeamWidth = this.beamWidth; + this.prevHeadSize = this.headSize; this.headOffsetX = nbt.hasKey("HeadOffsetX") ? nbt.getDouble("HeadOffsetX") : 0; this.headOffsetY = nbt.hasKey("HeadOffsetY") ? nbt.getDouble("HeadOffsetY") : 0; this.headOffsetZ = nbt.hasKey("HeadOffsetZ") ? nbt.getDouble("HeadOffsetZ") : 0; diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java index 817357d9b..db5e2eb2c 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java @@ -33,6 +33,8 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { // Disc shape properties private float discRadius = 1.0f; // Width of disc private float discThickness = 0.2f; // Height of disc + private float prevDiscRadius = 1.0f; + private float prevDiscThickness = 0.2f; // Boomerang owner-gone tracking private int returnOwnerNullTicks = 0; @@ -134,6 +136,10 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { @Override protected void updateProjectile() { + // Store previous values for interpolation + prevDiscRadius = discRadius; + prevDiscThickness = discThickness; + // Handle charging state (windup phase) if (isCharging()) { updateCharging(); @@ -347,7 +353,12 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { return discRadius; } + public float getInterpolatedDiscRadius(float partialTicks) { + return prevDiscRadius + (discRadius - prevDiscRadius) * partialTicks; + } + public void setDiscRadius(float radius) { + this.prevDiscRadius = this.discRadius; this.discRadius = radius; } @@ -355,7 +366,12 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { return discThickness; } + public float getInterpolatedDiscThickness(float partialTicks) { + return prevDiscThickness + (discThickness - prevDiscThickness) * partialTicks; + } + public void setDiscThickness(float thickness) { + this.prevDiscThickness = this.discThickness; this.discThickness = thickness; } @@ -443,6 +459,8 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { @Override protected void applyProjectileClientSyncData(NBTTagCompound nbt) { + prevDiscRadius = discRadius; + prevDiscThickness = discThickness; discRadius = nbt.getFloat("DiscRadius"); discThickness = nbt.getFloat("DiscThickness"); vertical = nbt.getBoolean("Vertical"); @@ -456,6 +474,8 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { this.boomerangDelay = nbt.hasKey("BoomerangDelay") ? nbt.getInteger("BoomerangDelay") : 40; this.discRadius = sanitize(nbt.hasKey("DiscRadius") ? nbt.getFloat("DiscRadius") : 1.0f, 1.0f, MAX_ENTITY_SIZE); this.discThickness = sanitize(nbt.hasKey("DiscThickness") ? nbt.getFloat("DiscThickness") : 0.2f, 0.2f, MAX_ENTITY_SIZE); + this.prevDiscRadius = this.discRadius; + this.prevDiscThickness = this.discThickness; this.vertical = nbt.hasKey("Vertical") ? nbt.getBoolean("Vertical") : false; this.returning = nbt.hasKey("Returning") && nbt.getBoolean("Returning"); // Charging state (common fields handled by base) diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java index 6e40ac999..f1eb9c617 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java @@ -33,6 +33,7 @@ public class EntityAbilityLaser extends EntityEnergyProjectile { // Laser-specific properties private float laserWidth = 0.2f; + private float prevLaserWidth = 0.2f; private float expansionSpeed = 2.0f; // Blocks per tick private float maxLength = 32.0f; // Maximum beam reach in blocks @@ -144,6 +145,9 @@ public class EntityAbilityLaser extends EntityEnergyProjectile { @Override protected void updateProjectile() { + // Store previous values for interpolation + prevLaserWidth = laserWidth; + if (isCharging()) { updateCharging(); return; @@ -703,7 +707,12 @@ public class EntityAbilityLaser extends EntityEnergyProjectile { return laserWidth; } + public float getInterpolatedLaserWidth(float partialTicks) { + return prevLaserWidth + (laserWidth - prevLaserWidth) * partialTicks; + } + public void setLaserWidth(float width) { + this.prevLaserWidth = this.laserWidth; this.laserWidth = width; } @@ -879,6 +888,7 @@ public class EntityAbilityLaser extends EntityEnergyProjectile { @Override protected void applyProjectileClientSyncData(NBTTagCompound nbt) { + prevLaserWidth = laserWidth; laserWidth = nbt.getFloat("LaserWidth"); expansionSpeed = nbt.getFloat("ExpansionSpeed"); maxLength = nbt.getFloat("MaxLength"); @@ -892,6 +902,7 @@ public class EntityAbilityLaser extends EntityEnergyProjectile { @Override protected void readProjectileNBT(NBTTagCompound nbt) { this.laserWidth = sanitize(nbt.hasKey("LaserWidth") ? nbt.getFloat("LaserWidth") : 0.2f, 0.2f, MAX_ENTITY_SIZE); + this.prevLaserWidth = this.laserWidth; this.expansionSpeed = sanitize(nbt.hasKey("ExpansionSpeed") ? nbt.getFloat("ExpansionSpeed") : 2.0f, 0.1f, MAX_ENTITY_SIZE); this.maxLength = sanitize(nbt.hasKey("MaxLength") ? nbt.getFloat("MaxLength") : 32.0f, 1.0f, MAX_ENTITY_SIZE); this.dirX = nbt.getDouble("DirX"); diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java index 5764bf0af..702c62c4d 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java @@ -738,8 +738,8 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility { motionY = nbt.getDouble("MotionY"); motionZ = nbt.getDouble("MotionZ"); syncPositionStateToCurrent(true); - // Size & visual - setProjectileSize(nbt.getFloat("Size")); + // Size & visual (set target only - let the lerp in onUpdate smooth the transition) + this.size = nbt.getFloat("Size"); displayData.setRotationSpeed(nbt.getFloat("RotationSpeed")); displayData.setInnerAlpha(nbt.getFloat("InnerAlpha")); displayData.setOuterColorEnabled(nbt.getBoolean("OuterColorEnabled"));