diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java index 4a9dc915..db9f7d5e 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java @@ -11,12 +11,10 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.*; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; import com.minelittlepony.unicopia.entity.player.Pony; -import com.minelittlepony.unicopia.particle.ParticleHandle; -import com.minelittlepony.unicopia.particle.SphereParticleEffect; import com.minelittlepony.unicopia.particle.UParticles; -import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.ProjectileDelegate; +import com.minelittlepony.unicopia.util.shape.Sphere; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; @@ -48,11 +46,11 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, .with(Trait.POWER, 1) .build(); - protected final ParticleHandle particlEffect = new ParticleHandle(); - private final Timer timer; private int struggles; + + private float prevRadius; private float radius; protected BubbleSpell(CustomisedSpellType type) { @@ -66,6 +64,10 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, return timer; } + public float getRadius(float tickDelta) { + return MathHelper.lerp(tickDelta, prevRadius, radius); + } + @Override public boolean apply(Caster source) { @@ -95,14 +97,19 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, public boolean tick(Caster source, Situation situation) { if (situation == Situation.PROJECTILE) { - - source.spawnParticles(ParticleTypes.BUBBLE, 2); + source.spawnParticles(UParticles.BUBBLE, 2); return true; } timer.tick(); - if (timer.getTicksRemaining() <= 0) { + boolean done = timer.getTicksRemaining() <= 0; + + source.spawnParticles(source.getOriginVector().add(0, 1, 0), new Sphere(true, radius * (done ? 0.25F : 0.5F)), done ? 13 : 1, pos -> { + source.addParticle(done ? ParticleTypes.BUBBLE_POP : UParticles.BUBBLE, pos, Vec3d.ZERO); + }); + + if (done) { return false; } @@ -116,7 +123,7 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, source.asEntity().fallDistance = 0; - Vec3d origin = source.getOriginVector(); + prevRadius = radius; if (source instanceof Pony pony && pony.sneakingChanged() && pony.asEntity().isSneaking()) { setDirty(); @@ -128,18 +135,11 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, } } - particlEffect.update(getUuid(), source, spawner -> { - spawner.addParticle(new SphereParticleEffect(UParticles.SPHERE, 0xFFFFFF, 0.3F, 0, new Vec3d(0, radius / 2F, 0)), origin, Vec3d.ZERO); - }).ifPresent(p -> { - p.setAttribute(Attachment.ATTR_RADIUS, radius); - }); - return !isDead(); } @Override protected void onDestroyed(Caster source) { - particlEffect.destroy(); if (source.asEntity() instanceof LivingEntity l) { MODIFIERS.forEach((attribute, modifier) -> { if (l.getAttributes().hasAttribute(attribute)) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java index 98046073..1d91a1d5 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java @@ -10,6 +10,7 @@ import com.minelittlepony.unicopia.block.cloud.CloudChestBlock; import com.minelittlepony.unicopia.client.particle.ChangelingMagicParticle; import com.minelittlepony.unicopia.client.particle.CloudsEscapingParticle; import com.minelittlepony.unicopia.client.particle.DiskParticle; +import com.minelittlepony.unicopia.client.particle.FloatingBubbleParticle; import com.minelittlepony.unicopia.client.particle.GroundPoundParticle; import com.minelittlepony.unicopia.client.particle.HealthDrainParticle; import com.minelittlepony.unicopia.client.particle.LightningBoltParticle; @@ -65,6 +66,7 @@ public interface URenderers { static void bootstrap() { ParticleFactoryRegistry.getInstance().register(UParticles.UNICORN_MAGIC, createFactory(MagicParticle::new)); ParticleFactoryRegistry.getInstance().register(UParticles.CHANGELING_MAGIC, createFactory(ChangelingMagicParticle::new)); + ParticleFactoryRegistry.getInstance().register(UParticles.BUBBLE, createFactory(FloatingBubbleParticle::new)); ParticleFactoryRegistry.getInstance().register(UParticles.RAIN_DROPS, createFactory(RaindropsParticle::new)); ParticleFactoryRegistry.getInstance().register(UParticles.HEALTH_DRAIN, createFactory(HealthDrainParticle::create)); ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_RING, RainboomParticle::new); diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/FloatingBubbleParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/FloatingBubbleParticle.java new file mode 100644 index 00000000..68d51be7 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/FloatingBubbleParticle.java @@ -0,0 +1,31 @@ +package com.minelittlepony.unicopia.client.particle; + +import net.minecraft.client.particle.ParticleTextureSheet; +import net.minecraft.client.particle.SpriteBillboardParticle; +import net.minecraft.client.particle.SpriteProvider; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.ParticleTypes; + +public class FloatingBubbleParticle extends SpriteBillboardParticle { + public FloatingBubbleParticle(ParticleEffect effect, SpriteProvider provider, ClientWorld clientWorld, double x, double y, double z, double dX, double dY, double dZ) { + super(clientWorld, x, y, z, dX, dY, dZ); + setSprite(provider); + scale((float)clientWorld.random.nextTriangular(1F, 0.5F)); + this.velocityX *= -0.1F; + this.velocityY *= -0.1F; + this.velocityZ *= -0.1F; + this.maxAge *= 3; + } + + @Override + public ParticleTextureSheet getType() { + return ParticleTextureSheet.PARTICLE_SHEET_OPAQUE; + } + + @Override + public void markDead() { + super.markDead(); + world.addParticle(ParticleTypes.BUBBLE_POP, x, y, z, 0, 0, 0); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/BubbleSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/BubbleSpellRenderer.java new file mode 100644 index 00000000..d15863b7 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/BubbleSpellRenderer.java @@ -0,0 +1,41 @@ +package com.minelittlepony.unicopia.client.render.spell; + +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.effect.BubbleSpell; +import com.minelittlepony.unicopia.client.gui.DrawableUtil; +import com.minelittlepony.unicopia.client.render.RenderLayers; +import com.minelittlepony.unicopia.client.render.model.SphereModel; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.RotationAxis; + +public class BubbleSpellRenderer implements SpellRenderer { + @Override + public void render(MatrixStack matrices, VertexConsumerProvider vertices, BubbleSpell spell, Caster caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { + matrices.push(); + double height = caster.asEntity().getEyeY() - caster.getOriginVector().y; + matrices.translate(0, height * 0.5F, 0); + + float radius = spell.getRadius(tickDelta) * 0.7F; + + VertexConsumer buffer = vertices.getBuffer(RenderLayers.getMagicNoColor()); + + Entity cameraEntity = MinecraftClient.getInstance().getCameraEntity(); + + matrices.push(); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-45)); + matrices.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(45 + cameraEntity.getYaw(tickDelta))); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-cameraEntity.getPitch(tickDelta))); + + new SphereModel(40, 40, DrawableUtil.PI * 0.25F).render(matrices, buffer, light, 0, radius - 0.1F, 0.9F, 0.9F, 1, 0.3F); + matrices.pop(); + + SphereModel.SPHERE.render(matrices, buffer, light, 0, radius, 0.9F, 0.9F, 1, 0.25F); + + matrices.pop(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java b/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java index 186be3e0..f1e88314 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java @@ -12,6 +12,7 @@ public interface UParticles { ParticleType UNICORN_MAGIC = register("unicorn_magic", FabricParticleTypes.complex(MagicParticleEffect.FACTORY)); DefaultParticleType CHANGELING_MAGIC = register("changeling_magic", FabricParticleTypes.simple()); + DefaultParticleType BUBBLE = register("bubble", FabricParticleTypes.simple()); ParticleType RAINBOOM_RING = register("rainboom_ring", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY)); DefaultParticleType RAINBOOM_TRAIL = register("rainboom_trail", FabricParticleTypes.simple()); diff --git a/src/main/resources/assets/unicopia/particles/bubble.json b/src/main/resources/assets/unicopia/particles/bubble.json new file mode 100644 index 00000000..21bb4eeb --- /dev/null +++ b/src/main/resources/assets/unicopia/particles/bubble.json @@ -0,0 +1,5 @@ +{ + "textures": [ + "minecraft:bubble" + ] +}