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\$
  • \$\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 '15 at 19:22
  • \$\begingroup\$ Do you know what % does? \$\endgroup\$ – user253751 Nov 8 '15 at 3:06
  • \$\begingroup\$ I knew my question was wrong and yes I know what it is. \$\endgroup\$ – SMKS_ARTS Nov 12 '15 at 18:14
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
    \$\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\$ – Niet the Dark Absol Nov 7 '15 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\$ – Jonas Malaco Nov 7 '15 at 19:06
6
\$\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\$
  • \$\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 '15 at 11:14
  • \$\begingroup\$ In Haxe, case body expressions never fall through. \$\endgroup\$ – Jonas Malaco Nov 7 '15 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 '15 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 '15 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 '15 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
    \$\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\$ – Ilmari Karonen Nov 8 '15 at 2:22
2
\$\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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.