3
\$\begingroup\$

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);
}
\$\endgroup\$
3
  • \$\begingroup\$ 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? \$\endgroup\$
    – Anko
    Nov 7, 2015 at 19:22
  • \$\begingroup\$ Do you know what % does? \$\endgroup\$
    – user253751
    Nov 8, 2015 at 3:06
  • \$\begingroup\$ I knew my question was wrong and yes I know what it is. \$\endgroup\$
    – SMKS_ARTS
    Nov 12, 2015 at 18:14

5 Answers 5

1
\$\begingroup\$

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.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ 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. \$\endgroup\$ Nov 7, 2015 at 17:03
  • \$\begingroup\$ @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. \$\endgroup\$ Nov 7, 2015 at 19:06
5
\$\begingroup\$

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
}
\$\endgroup\$
7
  • \$\begingroup\$ +1, nice answer. Though I would hesitate to recommend people new to programming use case drop-through. It's dangerous. \$\endgroup\$
    – Almo
    Nov 7, 2015 at 11:14
  • \$\begingroup\$ In Haxe, case body expressions never fall through. \$\endgroup\$ Nov 7, 2015 at 11:18
  • \$\begingroup\$ @jonasmalacofilho Thanks, edited it. I don't know HAXE though, is the rest of the syntax correct? \$\endgroup\$
    – LukeG
    Nov 7, 2015 at 11:23
  • \$\begingroup\$ @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. \$\endgroup\$
    – FooBar
    Nov 7, 2015 at 17:10
  • \$\begingroup\$ @FooBar I guess he meant that I attached multiple cases to the same statement, which i edited out. \$\endgroup\$
    – LukeG
    Nov 7, 2015 at 18:17
4
\$\begingroup\$

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.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ +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. \$\endgroup\$ Nov 8, 2015 at 2:22
1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .