# Want to play 1 of 3 tracks depending on current level

I want to play a gameplay music track depending on what the current level is.

E.g.

1 - Play track 1

2 - Play track 1

3 - Play track 2

4 - Play track 2

5 - Play track 3

repeat...

6 - Play track 1

7 - Play track 1

8 - Play track 2

9 - Play track 2

10 - Play track 3

This is what I have, but problem is track 2 will be used at level 6 when it should be track 1.

public static function playGameplayMusic(waveId:Int):Void
{
var gamePlayTrackId:Int;

if (waveId % 5 == 0) {
gamePlayTrackId = 3;
} else if (waveId % 3 == 0 || waveId % 4 == 0) {
gamePlayTrackId = 2;
} else {
gamePlayTrackId = 1;
}

trace('playing gameplay track: ' + gamePlayTrackId);

SoundPlayer.playMusicByName('gameplay/' + gamePlayTrackId, false);
}


Update:

Went with this. Thanks for all your contributions!

public static function playGameplayMusic(waveId:Int):Void
{
var gamePlayTrackId:Int = Math.ceil(((waveId - 1) % 5 + 1) / 2);

SoundPlayer.playMusicByName('gameplay/' + gamePlayTrackId, false);
}

• The core of this question seems to be a numeric algorithm that isn't specific to game development, or indeed to playing music, so the title is quite misleading. Any way this could be edited to clarify?
– Anko
Commented Nov 7, 2015 at 19:22
• Do you know what % does? Commented Nov 8, 2015 at 3:06
• I knew my question was wrong and yes I know what it is. Commented Nov 12, 2015 at 18:14

You need to combine a modulo (for the wrap-around) and a division (for the duplication of tracks). With some testing I got to:

static function track(level:Int):Int
{
return Math.ceil(((level - 1) % 5 + 1) / 2);
}


(live example on Try Haxe)

The idea is to divide a wrap-around, adjusting for no zeros. There might be a way to simplify this though.

• Does Haxe not have a switch statement that you can just do switch((level-1)%5) on? (Please forgive my ignorance if there is no such statement, but I know precisely nothing about Haxe. Commented Nov 7, 2015 at 17:03
• @NiettheDarkAbsol, Haxe does have a switch statement, and that might make things more readable. Performance varies between targets, with Math.ceil being faster in JS and switch in the other platforms I tested. Commented Nov 7, 2015 at 19:06

This question would probably be better suited at StackOverflow.

That being said: You are using the wrong modulo. Pseudocode:

n = waveID % 5;
n == 0 => Track3
n == 1 || n == 2 => Track1
n == 3 || n == 4 => Track2


If you use modulo you always have to use the size of you collection/repeating pattern (in this case 5). Furthermore I would recommend enumerating the levels beginning at 0, which shifts the above code around to:

n = waveID % 5;
n == 0 || n == 1 => Track1
n == 2 || n == 3 => Track2
n == 4 => Track3


The cleanest way to do this part is probably (Edit: adjusted to HAXE and removed case drop, thanks to jonasmalacofilho):

var n = waveID % 5;
switch(n){
case 0:
gamePlayTrackId = 1;
case 1:
gamePlayTrackId = 1;
case 2:
gamePlayTrackId = 2;
case 3:
gamePlayTrackId = 2;
case 4:
gamePlayTrackId = 3;
default:
//throw exception
}

• +1, nice answer. Though I would hesitate to recommend people new to programming use case drop-through. It's dangerous.
– Almo
Commented Nov 7, 2015 at 11:14
• In Haxe, case body expressions never fall through. Commented Nov 7, 2015 at 11:18
• @jonasmalacofilho Thanks, edited it. I don't know HAXE though, is the rest of the syntax correct? Commented Nov 7, 2015 at 11:23
• @Almo Registered here to say this: I would never recommend anyone to drop cases. //should not occur is almost as long as raise Exception(), or whatever the language-equivalent is. If you do a mistake only with every 1000th switch-routine you set up, this is still saving you a lot of time. Commented Nov 7, 2015 at 17:10
• @FooBar I guess he meant that I attached multiple cases to the same statement, which i edited out. Commented Nov 7, 2015 at 18:17

I don't know enough haxe to make this code better, but I would probably just do

var tracklist = [3, 1, 1, 2, 2];
gamePlayTrackId = tracklist[waveId % 5];


You can probably improve this by making tracklist static or any number of ways.
I'm still learning though, so look at the comments before you implement anything.

• +1, this should be the accepted answer. You might want to consider using tracklist[(waveId - 1) % 5] and moving the 3 to the end of the list, just for the sake of clarity, though. Commented Nov 8, 2015 at 2:22

You're getting problems with higher numbers being multiples of more than one of the numbers you check. 6 is not just going to trip the last else, it will also trip the % 3 == 0 one. I might do it this way:

StartGame()
{
m_musicLevel = 1;
m_track = playGameplayMusic(1);
}

NextLevel()
{
m_musicLevel++;
if(m_musicLevel > 5)
{
m_musicLevel = 1;
}
m_track = playGameplayMusic(m_musicLevel);
}


This means your playGameplayMusic function will only ever see levels 1-5. It's not super-elegant, but it's easy to understand and it will work.

If your levels are procedural / infinite, then the using the chosen method is good.

If you have a limited set of levels (i.e., only 10), then just associate the track choice with the level, hard-coded or preferably stored in the data that is loaded per level.