I’m making a VR game and I made a script that uses coroutines to determine when a sound has ended and will call an event when a sound ends. The project I made works very well when I play it in the unity editor. However, when I make a build of my project, the coroutine functions don’t seem to work. I noticed the game doesn’t recognize when sound ends.
I added some debug logs and created a development build to see what goes wrong in an actual build. The logs for dev builds are hard to read, but I noticed that I seems like more specifically, the WaitForSeconds and WaitUntil functions are not being called.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
public class AnnunPanelQuestStep : QuestStep
{
private bool isAnnunPanelTested = false;
[SerializeField]
private XRBaseInteractable annunPanelTestButton;
[SerializeField]
private AudioClip testButtonClip;
private AudioSource annunPanelAudioSource;
[SerializeField]
private int annunPanelCheckedScore = 5;
private void OnEnable()
{
annunPanelTestButton = interactables[0];
GameEventsManager.instance.soundEvents.onSFXEnded += SetAnnunPanelBool;
annunPanelTestButton.selectEntered.AddListener(AnnunPanelTestStart);
annunPanelTestButton.selectExited.AddListener(AnnunPanelTestStop);
}
private void OnDisable()
{
GameEventsManager.instance.soundEvents.onSFXEnded -= SetAnnunPanelBool;
annunPanelTestButton.selectEntered.AddListener(AnnunPanelTestStart);
annunPanelTestButton.selectExited.RemoveListener(AnnunPanelTestStop);
}
private void AnnunPanelTestStart(SelectEnterEventArgs arg0)
{
SoundFXManager.Instance.PlaySFXClip(null, testButtonClip,
arg0.interactableObject.transform, ref annunPanelAudioSource);
}
private void AnnunPanelTestStop(SelectExitEventArgs arg0)
{
annunPanelAudioSource.Pause();
if (isAnnunPanelTested)
{
Debug.Log("[Game] Annunciator panel released at the right time");
DisableInteractableOutline(arg0);
QuestStepTotalScore += annunPanelCheckedScore;
FinishQuestStep();
}
}
private void SetAnnunPanelBool(float timeToDestroyAudio)
{
isAnnunPanelTested = true;
StartCoroutine(WaitAndRestartAnnunPanelTest(timeToDestroyAudio));
}
private IEnumerator WaitAndRestartAnnunPanelTest(float timeToDestroyAudio)
{
//yield return new WaitForSeconds(timeToDestroyAudio);
while(timeToDestroyAudio > 0)
{
timeToDestroyAudio -= Time.deltaTime;
yield return null;
}
if(annunPanelTestButton.isSelected)
{
isAnnunPanelTested = false;
Debug.Log("[Game] Annunciator panel held past stopping time");
SoundFXManager.Instance.PlaySFXClip(null, testButtonClip,
annunPanelTestButton.transform, ref annunPanelAudioSource);
}
}
}
This script is used for determining a VR button’s behaviours. When you press the VR button, a sound is played. When you release the button the sound abruptly stops. You are supposed to press the button until the sound ends. Once you release the button after the sound ends, you can advance to the next quest. If you keep holding the button when the sound ends, the sound will restart after “timeToDestroyAudio” seconds, and the audio is played again. Then you have to hold the button again until it ends and release it to complete the quest.
One of the functions called SetAnnunPanelBool() is a subscriber to when the sound ends and will set the VR button to completed when the sound ends and start another coroutine that waits and checks if you are still holding the button to set the VR button to uncompleted.
public AudioSource PlaySFXClip(string questId, AudioClip audioClip, Transform spawnTransform,
ref AudioSource referencedAudioSource, float volume = 1f)
{
if(questId != null)
{
GameEventsManager.instance.soundEvents.SFXQuestBegin(questId);
}
else
{
GameEventsManager.instance.soundEvents.SFXBegin();
}
// spawn the sound gameobject
AudioSource audioSource = Instantiate(soundFXObject, spawnTransform.position, Quaternion.identity);
referencedAudioSource = audioSource;
// assign the audioClip
audioSource.clip = audioClip;
// assign volume
audioSource.volume = volume;
float clipLength = 0f;
if (audioClip != null)
{
// play sound
audioSource.Play();
// get length of the sound FX clip
clipLength = audioSource.clip.length;
}
StartCoroutine(WaitForSoundToEnd(questId, clipLength, audioSource));
return audioSource;
}
This is how the soundFX clip works and
private IEnumerator WaitForSoundToEnd(string questId, float clipLength, AudioSource audioSource)
{
yield return new WaitUntil(() => !audioSource.isPlaying);
if(audioSource.clip != null)
{
//Debug.Log(audioSource.time + " " + audioSource.clip.name + " " + audioSource.clip.length);
}
float timeToDestroy = 1f;
if (questId != null)
{
GameEventsManager.instance.soundEvents.SFXQuestEnded(questId);
Destroy(audioSource.gameObject, timeToDestroy);
}
else if(questId == null && audioSource.time >= clipLength) // In this case, AudioSource is not paused (it is completed)
{
Debug.Log("[Game] non-quest step related SFX played successfully");
GameEventsManager.instance.soundEvents.SFXEnded(timeToDestroy);
Destroy(audioSource.gameObject, timeToDestroy);
}
else
{
Debug.Log("[Game] Annunciator panel stopped prematurely");
Destroy(audioSource.gameObject, timeToDestroy);
}
}
This is the coroutine that is called as soon as you play a sound that waits for the sound to end in order to invoke an event.
Does anyone know why coroutines are not being recognized in my unity build?