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
  4. Dismiss Notice

Prevent random sounds from repeating or alternating

Discussion in 'Scripting' started by Zaffer, May 20, 2015.

  1. Zaffer

    Zaffer

    Joined:
    Oct 21, 2010
    Posts:
    266
    Hi, I have a project where I want 8 sounds to play randomly without too much repetition. I have code that prevents the same sound from playing twice in a row (see below). Can someone help me with code that will prevent the same sounds from alternating. In other words, I would not like: sound 1, sound 5, sound 1, but would prefer: sound 1, sound 5, sound 3, etc. Thanks.
    Code (CSharp):
    1. void CheckMusic(){  
    2.         if(musicSwitch && !GetComponent<AudioSource>().isPlaying){
    3.             int i = Random.Range(0, flowerNotes.Length);
    4.             if(i == lastFlowerNote || i == (lastFlowerNote + 1)){
    5.                 i = (i + 1) % flowerNotes.Length;
    6.             }
    7.  
    8.             GetComponent<AudioSource>().PlayOneShot(flowerNotes[i]);
    9.             Debug.Log(flowerNotes[i]);
    10.             lastFlowerNote = i;
    11.  
    12.             //Invoke("CheckMusic", Random.Range(3.0f, 4.0f));
    13.             Invoke("CheckMusic", 4.8f);
    14.         }
    15.         else {
    16.             CancelInvoke("CheckMusic"); // make sure the cycle stops
    17.             GetComponent<AudioSource>().Stop();  // stop the current audio
    18.         }
     
  2. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    you might want to consider a 2 play list approach.

    ListA start with the clips in order, ListB is empty.

    You now pick a random song from A, play it, take it out of A and put it in B. When A is empty get from B, when B is empty get from A.

    Essentially the play list remains random, but each song will only be played once until every other song has been played.
     
    WheresMommy and karl_jones like this.
  3. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,731
    I use something like this for random sounds that I don't want to have play twice in a row.

    Code (CSharp):
    1.  
    2. [SerializeField] AudioClip[] stepSounds;
    3. float timeStepSoundPlayed;
    4. AudioSource aSource;
    5. void Awake () {
    6.      aSource = GetComponent<AudioSource>();
    7. }
    8. void Update () {
    9.     PlayFootStepSound();
    10. }
    11. public void PlayFootStepSound()
    12. {
    13.     if(Time.time-timeStepSoundPlayed<0.25f) return;
    14.     int n = Random.Range(1, stepSounds.Length);
    15.     AudioClip clip = stepSounds[n];
    16.     aSource.PlayOneShot(clip);
    17.     stepSounds[n]=stepSounds[0];
    18.     stepSounds[0]=clip;
    19.     timeStepSoundPlayed = Time.time;
    20. }
    21.  
     
  4. Zaffer

    Zaffer

    Joined:
    Oct 21, 2010
    Posts:
    266
    Hi LeftyRighty and Munchy, Thanks for your ideas. I'm working on LeftyRighty's ListA and ListB idea right now. I'll post if/when I get something to work.
    Zaffer
     
  5. Zaffer

    Zaffer

    Joined:
    Oct 21, 2010
    Posts:
    266
    Hi LeftyRighty, Thanks so much, your idea for having two lists works really well at randomizing the sounds -- just one problem. I've written code that tells the program to switch lists when one list's Count reaches zero. The problem is that the second list starts before the last sound of the first list has played so I get two sounds at once -- not good. My code is below. I've tried various strategies including rearranging the code order and trying a yield statement, but I can't find anything that works. Help will be greatly appreciated. Thanks. Zaffer

    Code (CSharp):
    1. void CheckMusic(){  
    2.         if(musicSwitch && !GetComponent<AudioSource>().isPlaying){
    3.             if(whichList == "ListA"){
    4.                 int i = Random.Range(0, harpNotesA.Count);
    5.                 if(i == lastHarpNoteA){
    6.                     i = (i + 1) % harpNotesA.Count;
    7.                 }
    8.                 GetComponent<AudioSource>().PlayOneShot(harpNotesA[i]);
    9.                 Debug.Log(harpNotesA[i]);
    10.                 lastHarpNoteA = i;
    11.  
    12.                 AudioClip toTransferA = harpNotesA[lastHarpNoteA];
    13.                 harpNotesA.RemoveAt(lastHarpNoteA);
    14.                 harpNotesB.Add(toTransferA);
    15.                
    16.                 if(harpNotesA.Count == 0){
    17.                     WaitForABit();
    18.                     whichList = "ListB";
    19.                 }
    20.             }
    21.  
    22.             if(whichList == "ListB"){
    23.                 int j = Random.Range(0, harpNotesB.Count);
    24.                 if(j == lastHarpNoteB){
    25.                     j = (j + 1) % harpNotesB.Count;
    26.                 }
    27.                 GetComponent<AudioSource>().PlayOneShot(harpNotesB[j]);
    28.                //Debug.Log(harpNotesB[j]);
    29.                 lastHarpNoteB = j;
    30.  
    31.                 AudioClip toTransferB = harpNotesB[lastHarpNoteB];
    32.                 harpNotesB.RemoveAt(lastHarpNoteB);
    33.                 harpNotesA.Add(toTransferB);
    34.                
    35.                 if(harpNotesB.Count == 0){
    36.                     WaitForABit();
    37.                     whichList = "ListA";
    38.                 }  
    39.             }
    40.  
    41.             Invoke("CheckMusic", 4.8f);
    42.            // Debug.Log("Invoke CheckMusic");
    43.         }
    44.         else {
    45.             CancelInvoke("CheckMusic"); // make sure the cycle stops
    46.             GetComponent<AudioSource>().Stop();  // stop the current audio
    47.         }
    48.     }
    49.     IEnumerator WaitForABit(){
    50.         yield return new WaitForSeconds(4.8f);
    51.     }  
    52.  
     
  6. luke_2

    luke_2

    Joined:
    Nov 20, 2012
    Posts:
    29
    Swap lines
    1. WaitForABit();
    2. whichList = "ListB";
     
    Last edited: May 21, 2015
  7. Zaffer

    Zaffer

    Joined:
    Oct 21, 2010
    Posts:
    266
    Thanks Luke, I found the problem only presented itself at the end of the ListA code, not at the end of the ListB code. And it's due to the line, Invoke("CheckMusic", waitTime), being right after the ListB code, but not after the ListA code. The ListA code goes right to the ListB code instead of to Invoke("CheckMusic", waitTime), so that's why I'm getting two sounds playing at the same time at the end of ListA only. I couldn't figure out how to fix that, so I did a workaround and simply silenced the last ListA sound.


    Code (CSharp):
    1. void CheckMusic(){  
    2.  
    3.         if(musicSwitch && !GetComponent<AudioSource>().isPlaying){
    4.  
    5.             if(whichList == "ListA"){
    6.                 int i = Random.Range(0, harpNotesA.Count);
    7.                 if(i == lastHarpNoteA){
    8.                     i = (i + 1) % harpNotesA.Count;
    9.                 }
    10.                 GetComponent<AudioSource>().PlayOneShot(harpNotesA[i]);
    11.                 //Debug.Log(harpNotesA[i]);
    12.                 lastHarpNoteA = i;
    13.              
    14.                 AudioClip transferAtoB = harpNotesA[lastHarpNoteA];
    15.                 harpNotesA.RemoveAt(lastHarpNoteA);
    16.                 harpNotesB.Add(transferAtoB);
    17.                // Debug.Log("harpNotesA Count: " + harpNotesA.Count);
    18.              
    19.                 if(harpNotesA.Count == 0){
    20.                     GetComponent<AudioSource>().Stop();
    21.                     whichList = "ListB";
    22.                 }
    23.             }
    24.  
    25.             if(whichList == "ListB"){
    26.                 int j = Random.Range(0, harpNotesB.Count);
    27.                 if(j == lastHarpNoteB){
    28.                     j = (j + 1) % harpNotesB.Count;
    29.                 }
    30.                 GetComponent<AudioSource>().PlayOneShot(harpNotesB[j]);
    31.                 //Debug.Log(harpNotesB[j]);
    32.                 lastHarpNoteB = j;
    33.              
    34.                 AudioClip transferBtoA = harpNotesB[lastHarpNoteB];
    35.                 harpNotesB.RemoveAt(lastHarpNoteB);
    36.                 harpNotesA.Add(transferBtoA);
    37.                 //Debug.Log("harpNotesB Count: " + harpNotesB.Count);
    38.              
    39.                 if(harpNotesB.Count == 0){
    40.                     whichList = "ListA";
    41.                 }  
    42.             }
    43.  
    44.             Invoke("CheckMusic", waitTime);
    45.         }
    46.         else {
    47.             CancelInvoke("CheckMusic"); // make sure the cycle stops
    48.             GetComponent<AudioSource>().Stop();  // stop the current audio
    49.         }
    50.     }