diff --git a/src/main/java/com/minelittlepony/unicopia/USounds.java b/src/main/java/com/minelittlepony/unicopia/USounds.java index 72b61dca..3033f16c 100644 --- a/src/main/java/com/minelittlepony/unicopia/USounds.java +++ b/src/main/java/com/minelittlepony/unicopia/USounds.java @@ -10,6 +10,7 @@ public interface USounds { SoundEvent ENTITY_PLAYER_BATPONY_SCREECH = register("entity.player.batpony.screech"); SoundEvent ENTITY_PLAYER_REBOUND = register("entity.player.rebound"); SoundEvent ENTITY_PLAYER_PEGASUS_WINGSFLAP = register("entity.player.pegasus.wingsflap"); + SoundEvent ENTITY_PLAYER_PEGASUS_FLYING = register("entity.player.pegasus.flying"); SoundEvent ENTITY_PLAYER_PEGASUS_DASH = register("entity.player.pegasus.dash"); SoundEvent ENTITY_PLAYER_PEGASUS_MOLT = register("entity.player.pegasus.molt"); SoundEvent ENTITY_PLAYER_CHANGELING_BUZZ = register("entity.player.changeling.buzz"); diff --git a/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java b/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java index ff0887d9..f8b90fea 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java +++ b/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java @@ -75,8 +75,10 @@ public class ClientInteractionManager extends InteractionManager { PlayerPhysics physics = Pony.of(e).getPhysics(); return physics.isFlying() && physics.getFlightType() == FlightType.INSECTOID; }, USounds.ENTITY_PLAYER_CHANGELING_BUZZ, 1F, 1F, Random.create(seed))); - } else if (type == SOUND_GLIDING && source instanceof PlayerEntity) { + } else if (type == SOUND_GLIDING && source instanceof PlayerEntity && isClientPlayer((PlayerEntity) source)) { soundManager.play(new MotionBasedSoundInstance(SoundEvents.ITEM_ELYTRA_FLYING, (PlayerEntity)source, Random.create(seed))); + } else if (type == SOUND_GLIDING && source instanceof PlayerEntity) { + soundManager.play(new MotionBasedSoundInstance(USounds.ENTITY_PLAYER_PEGASUS_FLYING, (PlayerEntity)source, Random.create(seed))); } else if (type == SOUND_MAGIC_BEAM) { soundManager.play(new LoopedEntityTrackingSoundInstance(USounds.SPELL_CAST_SHOOT, 0.3F, 1F, source, seed)); } diff --git a/src/main/java/com/minelittlepony/unicopia/client/sound/FadeOutSoundInstance.java b/src/main/java/com/minelittlepony/unicopia/client/sound/FadeOutSoundInstance.java index f85b0278..78f81264 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/sound/FadeOutSoundInstance.java +++ b/src/main/java/com/minelittlepony/unicopia/client/sound/FadeOutSoundInstance.java @@ -81,6 +81,12 @@ public abstract class FadeOutSoundInstance extends MovingSoundInstance { progress = 0; } + protected void setVolume(float vol){ + sourceVolume = vol; + targetVolume = vol; + progress = 0; + } + private float getLerpedVolume() { float delta = MinecraftClient.getInstance().getTickDelta(); float interpolate = MathHelper.clamp(MathHelper.lerp(delta, prevProgress, progress) / transitionTicks, 0, 1); diff --git a/src/main/java/com/minelittlepony/unicopia/client/sound/MotionBasedSoundInstance.java b/src/main/java/com/minelittlepony/unicopia/client/sound/MotionBasedSoundInstance.java index 80823061..c9fca697 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/sound/MotionBasedSoundInstance.java +++ b/src/main/java/com/minelittlepony/unicopia/client/sound/MotionBasedSoundInstance.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.client.sound; import com.minelittlepony.unicopia.entity.player.Pony; +import net.minecraft.client.MinecraftClient; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.sound.SoundEvent; import net.minecraft.util.math.MathHelper; @@ -11,18 +12,30 @@ public class MotionBasedSoundInstance extends FadeOutSoundInstance { private final PlayerEntity player; + // Tune these if you want to change the way this sounds! + // Currently just hardcoded for flying because nothing else uses this class + private static final float MAX_VELOCITY = 1.5f; // Max velocity before we clamp volume (units/tick?) + private static final float VOLUME_AT_MAX = 1.0f; + private static final float ATTEN_EXPO = 2.0f; // Exponent for velocity based attenuation + private static final int FADEIN_TICKS = 20; // Ticks for fade-in + private static final float MIN_PITCH = 0.7f; // Pitch at 0-speed + private static final float MAX_PITCH = 2.6f; // Pitch at reference speed MAX_VELOCITY + private static final float MAX_RATE_TICKS = 20.0f; // How many ticks it takes to go from 0 to max volume (filter!) + private int tickCount; + private float currentVal; // Cache last tick's curve value public MotionBasedSoundInstance(SoundEvent sound, PlayerEntity player, Random random) { super(sound, player.getSoundCategory(), 0.1F, random); this.player = player; + currentVal = 0.0f; } @Override protected boolean shouldKeepPlaying() { ++tickCount; - if (player.isRemoved() || tickCount > 200) { + if (player.isRemoved()) { return false; } @@ -32,30 +45,41 @@ public class MotionBasedSoundInstance extends FadeOutSoundInstance { return false; } + // Update effect position x = ((float)player.getX()); y = ((float)player.getY()); - z = ((float)this.player.getZ()); + z = ((float)player.getZ()); + // Get velocity float f = (float)player.getVelocity().horizontalLength(); + + float lastVal = currentVal; + + // First we normalise the volume to the maximum velocity we're targeting, then we make it a curve. + // Drag is not linear, and neither is the woosh it produces, so a curve makes it sound more natural. + currentVal = (float) Math.pow(MathHelper.clamp(f / MAX_VELOCITY, 0, 1),ATTEN_EXPO); + + // Primitive lowpass filter/rate limiter thingy to rule out sudden jolts + currentVal = lastVal + MathHelper.clamp(currentVal - lastVal, -(1/MAX_RATE_TICKS), 1/MAX_RATE_TICKS); + if (f >= 1.0E-7D) { - volume = MathHelper.clamp(f / 4F, 0, 1); + // Multiply output volume by reference volume for overall gain control. + volume = currentVal * VOLUME_AT_MAX; } else { volume = 0.0F; } - if (tickCount < 20) { - volume = 0; - } else if (tickCount < 40) { - volume = (float)(volume * ((tickCount - 20) / 20D)); + // If we only just started playing, fade in! + if (tickCount < FADEIN_TICKS) { + volume *= ((tickCount) / (float)FADEIN_TICKS); } - if (volume > 0.8F) { - pitch = 1 + (volume - 0.8F); - } else { - pitch = 1; - } + // Control pitch with velocity + pitch = MathHelper.lerp(currentVal,MIN_PITCH,MAX_PITCH); - setTargetVolume(volume); + // Setting target volume every frame breaks interpolation. We set volume directly, + // so that FadeOutSoundInstance only handles stopping the sound with an actual fade out! + setVolume(volume); return true; } diff --git a/src/main/resources/assets/unicopia/sounds.json b/src/main/resources/assets/unicopia/sounds.json index 0d99b7a5..025ba179 100644 --- a/src/main/resources/assets/unicopia/sounds.json +++ b/src/main/resources/assets/unicopia/sounds.json @@ -21,6 +21,14 @@ "unicopia:woosh/woosh5" ] }, + "entity.player.pegasus.flying": { + "sounds": [ + { + "name": "unicopia:wind/flying_loop", + "volume": 0.6 + } + ] + }, "item.magic.aura": { "category": "player", "subtitle": "unicopia.subtitle.magic_aura", diff --git a/src/main/resources/assets/unicopia/sounds/wind/flying_loop.ogg b/src/main/resources/assets/unicopia/sounds/wind/flying_loop.ogg new file mode 100644 index 00000000..fb714c96 Binary files /dev/null and b/src/main/resources/assets/unicopia/sounds/wind/flying_loop.ogg differ