Search Unity

Coroutine issues on first few frames

Discussion in 'Scripting' started by Clydey2Times, Sep 12, 2019.

  1. Clydey2Times

    Clydey2Times

    Joined:
    Oct 24, 2017
    Posts:
    242
    I'm trying to make a character use a random audio clip every few seconds while idle. For the most part, my code works. However, when the game first time the coroutine is executed, the clips are rapidly being changed and played (cutting each other off). After this, everything seems to work as intended.

    Can anyone spot where I'm going wrong? Here's the relevant class:

    Code (CSharp):
    1.     [SerializeField] private AudioClip[] walkSounds, idleSounds, attackSounds;
    2.  
    3.     private AudioSource[] audioSources;
    4.     private Animator anim;
    5.     private NavMeshAgent enemyAgent;
    6.    
    7.     private void Start()
    8.     {
    9.         audioSources = GetComponents<AudioSource>();
    10.         anim = GetComponent<Animator>();
    11.         enemyAgent = GetComponent<NavMeshAgent>();
    12.     }
    13.  
    14.     private void Update()
    15.     {
    16.         if(!audioSources[0].isPlaying)
    17.         StartCoroutine(IdleAudio());
    18.     }
    19.  
    20.     private IEnumerator IdleAudio()
    21.     {
    22.        
    23.         yield return new WaitForSeconds(Random.Range(3, 5));
    24.  
    25.         if (IsIdle())
    26.         {
    27.            
    28.             audioSources[0].clip = idleSounds[Random.Range(0, idleSounds.Length - 1)];
    29.             audioSources[0].Play();
    30.         }
    31.                                
    32.     }
    33.  
    34.     private bool IsIdle()
    35.     {
    36.         if(enemyAgent.desiredVelocity.magnitude < 0.1f)
    37.         {
    38.             return true;
    39.         }
    40.         return false;
    41.     }
    Any help would be greatly appreciated.
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    You have a bunch of copies of the coroutine running in parallel, because during the 3-5 second wait, the audioSource[0] is still not playing.
    Make a bool to track whether this coroutine is running, and set that bool before you yield on line 23.
     
  3. Clydey2Times

    Clydey2Times

    Joined:
    Oct 24, 2017
    Posts:
    242
    Thanks for the response. How would I do that? Can I have the coroutine return a bool?

    Here's what I tried:

    Code (CSharp):
    1.     private void Update()
    2.     {
    3.  
    4.  
    5.         if (!crIsRunning)
    6.         {
    7.             crIsRunning = true;
    8.             StartCoroutine(IdleAudio());
    9.         }
    10.        
    11.     }
    12.  
    13.     private IEnumerator IdleAudio()
    14.     {
    15.        
    16.         yield return new WaitForSeconds(Random.Range(3, 5));
    17.  
    18.         if (IsIdle())
    19.         {
    20.            
    21.             audioSources[0].clip = idleSounds[Random.Range(0, idleSounds.Length - 1)];
    22.             audioSources[0].Play();
    23.         }
    24.         yield return new WaitForSeconds(1);
    25.         crIsRunning = false;
    26.                        
    27.     }
    I was sure that would work, but it doesn't. Can't figure out where I'm going wrong in my logic.
     
    Last edited: Sep 12, 2019
  4. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    That should work, assuming crIsRunning starts off at false. What do you mean by doesn't work - does it not run the coroutine at all, or does it still do the "clip rapidly change" thing?
     
  5. Clydey2Times

    Clydey2Times

    Joined:
    Oct 24, 2017
    Posts:
    242
    Yeah, I'm initialising it to false.

    The clips eventually start interrupting each other, so basically being changed and played rapidly. Can't figure out why.
     
  6. Clydey2Times

    Clydey2Times

    Joined:
    Oct 24, 2017
    Posts:
    242
    OK, I figured out what the problem is. It's rather irritating. Unity, for some reason, attached two copies of the class onto the game object, as well as two audio sources (not that the latter matters in this case).

    I don't know if you've had this happen, but I'll occasionally see multiple copies of a script on a game object.