Sound Trigger Issue in Unity

Hello everyone,

I’m having an issue with triggering a sound in Unity, and I’m hoping someone can help me figure out what I might be doing wrong.

I’m trying to make a monster play a sound when it first spots the player. I’m using FindObjectOfType<AudioManager>().Play("spotted"); in my script to trigger the sound. I’ve placed it in the section of my code where the monster should begin chasing the player. However, instead of playing the sound when the monster initially detects the player, it plays it after the player has hidden or escaped and the monster loses track of them.

Here’s a simplified version of my code where I’m triggering the sound:

if (hit.collider.gameObject.tag == "Player")
{
    walking = false;
    StopCoroutine("stayIdle");
    StopCoroutine("chaseRoutine");
    StartCoroutine("chaseRoutine");
    chasing = true;
    
    // Attempting to play the "spotted" sound
    FindObjectOfType<AudioManager>().Play("spotted");
}

The logic should, in theory, trigger the “spotted” sound as soon as the monster detects the player, but it doesn’t play at the right time. It only plays after the player breaks line of sight or hides, as if the sound is somehow delayed until the chasing phase is complete.

Has anyone encountered something similar, or does anyone have suggestions on what might be causing this? Could it be something to do with the order of code execution, or perhaps how I’m setting the chasing and idle states? Any insights would be greatly appreciated!

Here is the entire code if you need

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;

public class haterAI : MonoBehaviour
{
    public NavMeshAgent ai;
    public List<Transform> destinations;
    public Animator aiAnim;
    public float walkSpeed, chaseSpeed, minIdleTime, maxIdleTime, idleTime, sightDistance, catchDistance, chaseTime, minChaseTime, maxChaseTime, jumpscareTime;
    public bool walking, chasing;
    public Transform player;
    Transform currentDest;
    Transform previousDest;
    Vector3 dest;
    public Vector3 rayCastOffset;
    public string deathScene;
    public float aiDistance;
    public GameObject hideText, stopHideText;

    void Start()
    {
        walking = true;
        previousDest = null;
        currentDest = GetRandomDestination(); 
    }

    void Update()
    {
        Vector3 direction = (player.position - transform.position).normalized;
        RaycastHit hit;
        aiDistance = Vector3.Distance(player.position, this.transform.position);

        if (Physics.Raycast(transform.position + rayCastOffset, direction, out hit, sightDistance))
        {
            if (hit.collider.gameObject.tag == "Player")
            {
                walking = false;
                StopCoroutine("stayIdle");
                StopCoroutine("chaseRoutine");
                StartCoroutine("chaseRoutine");
                chasing = true;
            }
        }

        if (chasing == true)
        {
                
            dest = player.position;
            ai.destination = dest;
            ai.speed = chaseSpeed;
            aiAnim.ResetTrigger("walk");
            aiAnim.ResetTrigger("idle");
            aiAnim.SetTrigger("sprint");


            if (aiDistance <= catchDistance)
            {
                player.gameObject.SetActive(false);
                aiAnim.ResetTrigger("walk");
                aiAnim.ResetTrigger("idle");
                hideText.SetActive(false);
                stopHideText.SetActive(false);
                aiAnim.ResetTrigger("sprint");
                aiAnim.SetTrigger("jumpscare");
                StartCoroutine(deathRoutine());
                chasing = false;
            }
        }

        if (walking == true)
        {
            dest = currentDest.position;
            ai.destination = dest;
            ai.speed = walkSpeed;
            aiAnim.ResetTrigger("sprint");
            aiAnim.ResetTrigger("idle");
            aiAnim.SetTrigger("walk");

            if (ai.remainingDistance <= ai.stoppingDistance)
            {
                aiAnim.ResetTrigger("sprint");
                aiAnim.ResetTrigger("walk");
                aiAnim.SetTrigger("idle");
                ai.speed = 0;
                StopCoroutine("stayIdle");
                StartCoroutine("stayIdle");
                walking = false;
            }
        }
    }

    public void stopChase()
    {
        walking = true;
        chasing = false;
        StopCoroutine("chaseRoutine");
        currentDest = GetRandomDestination(); 
    }

    IEnumerator stayIdle()
    {
        idleTime = Random.Range(minIdleTime, maxIdleTime);
        yield return new WaitForSeconds(idleTime);
        walking = true;
        currentDest = GetRandomDestination(); 
    }

    IEnumerator chaseRoutine()
    {
        chaseTime = Random.Range(minChaseTime, maxChaseTime);
        yield return new WaitForSeconds(chaseTime);
        stopChase();
    }

    IEnumerator deathRoutine()
    {
        yield return new WaitForSeconds(jumpscareTime);
        SceneManager.LoadScene(deathScene);
    }

   
    Transform GetRandomDestination()
    {
        Transform newDest;

       
        do
        {
            newDest = destinations[Random.Range(0, destinations.Count)];
        } while (newDest == previousDest && destinations.Count > 1);

        previousDest = newDest; 
        return newDest;
    }
}

Thanks so much in advance for your help!

That would be my first intuition.

Generally speaking…

if you have to use StopCoroutine(); then coroutines are not the correct solution.

If you want to persist with all of this start/stop coroutine stuff it will be harder to debug what’s going on, but at the end of the day you will still need to debug it to find what is happening before you can begin to fix it.

By debugging you can find out exactly what your program is doing so you can fix it.

Use the above techniques to get the information you need in order to reason about what the problem is.

You can also use Debug.Log(...); statements to find out if any of your code is even running. Don’t assume it is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

Here’s more random coroutine reading.

Coroutines in a nutshell:

Splitting up larger tasks in coroutines:

Coroutines are NOT always an appropriate solution: know when to use them!

“Why not simply stop having so many coroutines ffs.” - orionsyndrome on Unity3D forums

Our very own Bunny83 has also provided a Coroutine Crash Course:

And another overview by Anders Malmgren:

3 Likes