Making an Underwater Music Effect in HaxeFlixel

Posted December 20, 2021

Hold up!

If you like 90s platformers, check out my new game Kid Bubblegum!

If you jump into the water in my game Go! Go! PogoGirl, you’ll notice that the music dynamically changes to sound like…well, to sound like you’re underwater.

This kind of effect is easily achievable with audio frameworks such as FMOD, but these are not only expensive but also not that easy to get running with HaxeFlixel (if at all). But then, how did I do it? It’s actually surprisingly simple to achieve!

First of all, you’ll need two versions of your music track: The regular one and the modified one. These have to have the exact same length, otherwise you’ll run into issues. Simply import your track into a tool like Dark Audacity, apply the desired effects and export it again. As for how to create an underwater effect…well, I’m not an audio guy, but you can find some pointers on reddit. I had my audio guy Reflekshun do it, to be perfectly honest.

Next, you need to know how to play music in HaxeFlixel at all. This is of course very easy: Simply call FlxG.sound.playMusic(track), with track being the path to your music asset. You can get more details on this in the official HaxeFlixel tutorial.

Now to make the magic happen. The basic idea is to simply play the underwater version of the track the moment players enter the water, and to switch back to the regular version once they leave the water. However, this would obviously mean that the music tracks will always start from the beginning, which isn’t what we want. The solution? Simply carry over the timestamp, so that the next track keeps playing where the previous one left off!

You could for example write a function like this:

public function hotSwitchToTrack(TrackToPlay:String)
{
	var t = FlxG.sound.music.time;
	FlxG.sound.playMusic(TrackToPlay);
	FlxG.sound.music.time = t;
}

You should of course only call this function when there is already a track playing, otherwise FlxG.sound.music will be null.

This function simply grabs the position in runtime of the current track, saves it in t, starts playing the new track and then skips ahead to the previously saved position! This is also why both tracks need to have the same length, as otherwise you’ll notice skips when switching between the tracks.

And that’s all there is to it, really! Kind of a dumb solution, but it works well. However, there is one issue that you might run into: Your game might lag for a second or so when you first switch tracks. This is because the second track has to be loaded into memory first, which can take a while.

But there is an easy way around that. Simply play all the needed tracks at the beginning of your state once, and immediately stop them with FlxG.sound.music.stop()! This way, all tracks will be loaded into memory and ready to be hotswapped whenever necessary.

Sometimes, dumb solutions are the best.

If you have any questions, comments or criticism, post them in the comments below or reach out to me on Twitter @ohsat_games!

Join my Discord Server!

Hang out, get news, be excellent!

Come hang out!

Want To Buy Me a Coffee?

Coffee rules, and it keeps me going! I'll take beer too, though.

Check out the rest of this tutorial series!

  • HaxeFlixel Crash Course: Make a Pong Game in Under 1 Hour
  • Pixel-Perfect 2D Water Shader
  • Collision and Overlap
  • Using Finite State Machines in HaxeFlixel
  • One-Way Collisions
  • Z-Sorting in HaxeFlixel
  • Making an Underwater Music Effect in HaxeFlixel
  • Quick Snow Effect
  • How to Implement Cheats
  • Using LDtk with FlxTilemap
  • Using a Texture Atlas
  • How To Make Your Own Haxe Library
  • By using the Disqus service you confirm that you have read and agreed to the privacy policy.

    comments powered by Disqus