Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Too many switch cases?

Discussion in 'Scripting' started by snakeeye98, Sep 2, 2019.

  1. snakeeye98

    snakeeye98

    Joined:
    Sep 2, 2019
    Posts:
    17
    Hello, I am currently working on my first game wich is working pretty fine already. Since the Main Features werde done, I decided to upgrade the amount of voice files.
    I have a rng generator as integer to calculate a number from 1 to 67 to choose the Audio file that should be played. Then I have a switch solution with 66 cases (0 also a case) . I tried it with just 5 before and it was perfect. But since the upgrade to 67 my game lags now everytime a new voice file gets chosen for like half a second. This leads to my implemented game timer not showing up correctly for half a second too.

    My general question now is: Is there a way to use this many sound files in unity more efficiently? Is there maybe even a way better way to implement this many switch cases? I am happy about every idea you can give me.
    Thank you!
     
  2. bobisgod234

    bobisgod234

    Joined:
    Nov 15, 2016
    Posts:
    1,042
    67 switch cases would be kind of a pain to maintain, but shouldn't cause any performance problems. Check the profiler to see what is going on.

    Consider refactoring your 67 switch cases somehow, for example, use an array to select the audio file.
     
    angrypenguin and snakeeye98 like this.
  3. CurtisMcGill

    CurtisMcGill

    Joined:
    Aug 7, 2012
    Posts:
    67
    What settings are the audio files 48K, etc, how big are they, how many seconds average and what format ie: mp3.

    You might need to edit your audio files, if they are 48k, 320 bit you might want to try a smaller setting, like 22k or 44K 128 bit. If you are not using doppler then you can easily convert to mono.

    Based on your answers, there is a best practice on unity settings, audio settings, and format.

    You can load them into an Audio Array and play them from the array. I made a radio script a few years back and I will try to dig it up and post the code.
     
    snakeeye98 likes this.
  4. CurtisMcGill

    CurtisMcGill

    Joined:
    Aug 7, 2012
    Posts:
    67
    I loaded my voices in resources\voices, this is the script that will load all the voices in an array. I trimmed it down from the multi-voice system to this.

    For performance, the audio file should be 22k (50% smaller) or 44k 128 bit and optional mono, which is 50% smaller and format wav.

    As for Unity settings, I won't get into all the differences, too big of a topic for the forums. Compressed In Memory and ADPCM Compression Format. ADPCM is around 3.5 times smaller than raw PCM and decompression algorithm will not consume as much CPU as Vorbis.

    Note: I made the global variables public for testing but when debugged, make them private.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Radio : MonoBehaviour
    5. {
    6.     // holds all voices
    7.     public Object[] Voices;
    8.    // what sound file we are playing
    9.     public int Voice;
    10.     // is voice system busy?
    11.     public bool IsBusy;
    12.     // how long to wait for next voice
    13.     public float NextTransmission = 2f;
    14.     // hold next voice time
    15.     public float NextTalkTime;
    16.  
    17.     void Start()
    18.     {
    19.         Voice = 0;
    20.         IsBusy = false;
    21.         Voices = Resources.LoadAll("Voices", typeof(AudioClip));
    22.     }
    23.  
    24.     void LateUpdate()
    25.     {
    26.         if (IsBusy || Time.time < NextTalkTime) return;
    27.         StartCoroutine(Playme());
    28.     }
    29.  
    30.     private IEnumerator Playme()
    31.     {
    32.         IsBusy = true;
    33.  
    34.         AudioClip audioTemp = (AudioClip) Voices[Voice];
    35.         GetComponent<AudioSource>().PlayOneShot(audioTemp);
    36.         yield return new WaitForSeconds(audioTemp.length - 0.1f);
    37.  
    38.         // increase voice by 1 to play next audio
    39.         Voice += 1;
    40.         NextTalkTime = Time.time + NextTransmission;
    41.         IsBusy = false;
    42.     }
    43. }
     
    Last edited: Sep 2, 2019
    snakeeye98 likes this.
  5. Boz0r

    Boz0r

    Joined:
    Feb 27, 2014
    Posts:
    419
    Could you post your code? Why are you using a switch instead of just having them in a list? And what are you doing in the switch?
     
    EdGunther and snakeeye98 like this.
  6. snakeeye98

    snakeeye98

    Joined:
    Sep 2, 2019
    Posts:
    17
    Thank you for all your answers. I guess I will try them now one by one and see what works for me.

    Since my code is quite big already I will try to break it down so posting it here becomes not as much of a pain:

    Code (CSharp):
    1. //Check Input
    2.         if (Input.GetKeyDown(neededPress)) {    //Correct Input
    3.      
    4.             rngSound = Random.Range(1,76);
    5.      
    6.             switch (rngSound) {        //Music RNG
    7.                 case 0:
    8.                 changeText.text = "AMAZING";
    9.                 amazing.Play();
    10.                 break;
    11.                 case 1:
    12.                 changeText.text = "AWESOME";
    13.                 awesome.Play();
    14.                 break;
    15.                 case 2:
    16.                 changeText.text = "MAGNIFICENT";
    17.                 magnificent.Play();
    18.                 break;
    19.                 case 3:
    20.                 changeText.text = "CRAZY";
    21.                 crazy.Play();
    22.                 break;
    23.                 case 4:
    24.                 changeText.text = "UNBELIEVABLE";
    25.                 unbelievable.Play();
    26.                 break;
    27.                 //.......................
    28.                 case 77:
    29.                 changeText.text = "YOU DID IT";
    30.                 youdidit.Play();
    31.                 break;
    32.             }
    33.      
    34.             StartCoroutine(wait_and_start_over()); //timer reset in here works without lag, from there on is a visual lag every time somewhere, but idk where exactly
    35.             neededPress = KeyCode.None;
    36.             timerEnabled = false;
    37.             score++; //Increase Score
    38.             scoreText.text = "Score: " + score;
    39.         }
    40.         else if (Input.anyKeyDown) {    //Wrong Input
    41.             fail_routine();        //substracts lives
    42.         }
    43.  
    44.  
    45.     }
    If you need any more of the code, let me know!
    The audio files do have a lenght of like 1-2 secs each, sometimes less.

    Thank you.

    EDIT: This is in my Update Function. The exact moment of lag is right after the sound file got played. So it still gets to play it - but since the amount of audio files are the only thing I changed in this build it has to do something with these.

    I am not really sure about the audio quality. I just recorded some samples with Audacity and left them at their standard options. (Size mostly 22 KB)
     
    Last edited: Sep 2, 2019
  7. snakeeye98

    snakeeye98

    Joined:
    Sep 2, 2019
    Posts:
    17
    I found a solution.

    The problem seemed to be that the Update Function was to overloaded with my 77 switch cases, so I decided to put the switch cases in a seperate function "void praise()". Now my timer runs fluidly. Even though I can not really understand why Unity struggles with "just" about 80 simple switch cases in its update function I am happy that it works well now. Another thing learned. :)

    Thank you for you help.
     
  8. EdGunther

    EdGunther

    Joined:
    Jun 25, 2018
    Posts:
    183
    Personally I would have made a string array and a clip array, the random number just choosing an index in those arrays.

    Look how much cleaner this code looks. Maintaining arrays like this is way easier than an uber-long switch statement.

    Code (CSharp):
    1. void Update
    2. {
    3.     if (Input.GetKeyDown(neededPress))   //Correct Input
    4.     {
    5.         PlayRandom(Random.Range(0, successStrings.Length));
    6.     }
    7. }
    8.  
    9. void PlayRandom(int rand)
    10. {
    11.     changeText.text = successStrings[rand];
    12.     successSoundClips[rand].Play();
    13. }
     
    Reedex and snakeeye98 like this.
  9. snakeeye98

    snakeeye98

    Joined:
    Sep 2, 2019
    Posts:
    17
    Thats a good point! Thank you, I will probably rewrite my code then.
     
  10. EdGunther

    EdGunther

    Joined:
    Jun 25, 2018
    Posts:
    183
    You could even create a class that contains a string and a clip and then only maintain one array of that class.
     
    SparrowGS, Munchy2007 and snakeeye98 like this.
  11. snakeeye98

    snakeeye98

    Joined:
    Sep 2, 2019
    Posts:
    17
    The problem with this solution seems to be that I still need a switch case to display every compliment as a text.
     
  12. EdGunther

    EdGunther

    Joined:
    Jun 25, 2018
    Posts:
    183
    I put text displays in line 11
     
    snakeeye98 likes this.
  13. EdGunther

    EdGunther

    Joined:
    Jun 25, 2018
    Posts:
    183
    Code (CSharp):
    1. //Here is where you put the compliment strings
    2. string[] successStrings = new string[] {"WOW", "COOL", "AMAZING"};
    3. public AudioClip[] successSoundClips = new AudioClip[3];
    4.  
    5. void Update
    6. {
    7.     if (Input.GetKeyDown(neededPress))   //Correct Input
    8.     {
    9.         PlayRandom(Random.Range(0, successStrings.Length));
    10.     }
    11. }
    12. void PlayRandom(int rand)
    13. {
    14.     //here is where those strings get displayed as text
    15.     changeText.text = successStrings[rand];
    16.     successSoundClips[rand].Play();
    17. }
     
    snakeeye98 likes this.
  14. EdGunther

    EdGunther

    Joined:
    Jun 25, 2018
    Posts:
    183
    Also, since your text is simply the name of the audiofile, you might be able to do something cheeky like
    changeText.text = SoundClips[rand].name.ToString();
    idk
     
    snakeeye98 likes this.
  15. snakeeye98

    snakeeye98

    Joined:
    Sep 2, 2019
    Posts:
    17
    Thanks I chose to write my array by hand because I have audio files like "youdidiit" that should be spelled "YOU DID IT". You still made my life a lot easier now. Its way easier to handle SoundClips than SoundSources, especially with this amount!
    So I now reduced my code to just a few lines and it works.

    Sadly the "lag thing" came back. After some more testing I realized that it wasnt consistent. There are two possibilities:
    1) I do not encounter any lag at all for the whole playtest
    2) I have a slight lag after nearly every soundeffect for the whole playtest. (this is more common)

    But since this is not as consistent as I thought I am wondering if there could be something with my PC hardware that leads to some inconsistencies while testing. It is definitely not a big problem, since it is just a visual radial timer lag (in the background the timer runs without a problem). But this still is something I need to adress sooner or later - maybe the problem lies somewhere completely different.

    I will dig deeper into this and also look into my other lines of code - if I find something I will post it here. If not I will probably create a new thread because it will probably be a bigger problem than just "too many switch cases".

    Thank you for your patience and have a great day!
     
  16. CurtisMcGill

    CurtisMcGill

    Joined:
    Aug 7, 2012
    Posts:
    67
    The lag is the delay in loading the file into memory uncompressing it and playing it. I went into a little detail in my post, but there are 3 audio load types and 6 performance configurations depending on Music or FX, size, etc. Aforementioned would prevent lag and increase performance.

    If I have time I will post an article on the settings.
     
    Last edited: Sep 4, 2019
    snakeeye98 likes this.
  17. CurtisMcGill

    CurtisMcGill

    Joined:
    Aug 7, 2012
    Posts:
    67
    Memory Matters
    Unity Knights

    All Audio Clips are imported by default with Decompress On Load Load Type and Vorbis Compression Format.


    These are default import settings.

    Be careful with this setting, if used on all audio clips (Unity does it by default!) could consume a large amount of your game’s memory!

    The original file size is computed to 35.9 MB and the imported size to 10.7 MB. This means that this Audio Clip will increase your game (archive) size by 10 megabytes, but playing it will require nearly 36 megabytes of RAM! This does not sound too scary if you’re building a game for PC where it is quite common to have 8 gigabytes of RAM, but mobile devices are still minimal in that manner.

    When Should I use a Specific Load Type?
    Let’s get this straight. Each Load Type and Compression Format combination can be used, and you’re the one who knows best which one should be chosen. There are three Load Types:

    Compressed In Memory – Audio Clip will be stored in RAM and will be uncompressed when played. Does not require additional memory for playing.
    Streaming – Audio Clip will be stored on a device persistent memory (hard drive, flash drive, etc.) and streamed when played. Does not require RAM for storing and playing (at least this value is not significant).
    Decompress On Load – Audio Clip will be stored in RAM uncompressed. This option requires the most memory but playing it will not need so much CPU power as the rest.

    So, which one to use? It depends…

    Music and Ambient Sounds
    Music is stored in long Audio Clips so that it can consume a lot of memory. You do not want music to be decompressed into the memory then played. You have two options here:

    1. Use Load Type Streaming and Compression Format Vorbis. This combination will use the least amount of memory but will require some CPU power and disk I/O throughput.

    2. Use Load Type Compressed In Memory and Compression Format Vorbis. The only difference from the first solution is that it will exchange the disk I/O with some memory requirement.

    Note that you can adjust the Quality slider to decrease compressed clip size in exchange of sound quality. Usually, 100 percent is a way too high. I would recommend something around 70 percent.

    Note that if you have more than two music/ambient sounds clips playing like this, it can consume a severe amount of CPU power.

    Sound Effects
    Sound effects are usually short or medium Audio Clips. These can be played frequently or rarely. Here are some rules:

    1. For regularly played and short Audio Clips use Decompress On Load and PCM or ADPCM Compression Format. When PCM is chosen, no decompression is needed, and if an audio clip is short, it will load very quickly. You can also use ADPCM. It requires decompression, but it is much lighter to decompress than Vorbis.

    2. For frequently played but medium Audio Clips use Compressed In Memory and ADPCM Compression Format. ADPCM is around 3.5 times smaller than raw PCM, and decompression algorithm will not consume as much CPU as Vorbis.

    3. For rarely played and short Audio Clips use Compressed In Memory and ADPCM. For the same reason, as described in point 2.

    4. For rarely played and medium Audio Clips use Compressed In Memory and Vorbis Compression Format. This SFX might be too long to be stored using ADPCM and played too rarely, therefore additional CPU power required to decompress would not be such pain.
     
    Last edited: Sep 4, 2019
    snakeeye98 likes this.
  18. snakeeye98

    snakeeye98

    Joined:
    Sep 2, 2019
    Posts:
    17
    This is an amazing guide! Thank you very much for your effort! You helped me a lot to understand Unity.
     
  19. EdGunther

    EdGunther

    Joined:
    Jun 25, 2018
    Posts:
    183
    That's a pretty good guide. Is there a link to this?
     
  20. CurtisMcGill

    CurtisMcGill

    Joined:
    Aug 7, 2012
    Posts:
    67
    That is an article I downloaded a few years ago and I am not sure of the address or if it is still online. I can post the entire larger article and I have the Unity's Knights second part of the article.