-
-
Save kurtdekker/0da9a9721c15bd3af1d2ced0a367e24e to your computer and use it in GitHub Desktop.
using UnityEngine; | |
using System.Collections; | |
public class CallAfterDelay : MonoBehaviour | |
{ | |
float delay; | |
System.Action action; | |
// Will never call this frame, always the next frame at the earliest | |
public static CallAfterDelay Create( float delay, System.Action action) | |
{ | |
CallAfterDelay cad = new GameObject("CallAfterDelay").AddComponent<CallAfterDelay>(); | |
cad.delay = delay; | |
cad.action = action; | |
return cad; | |
} | |
float age; | |
void Update() | |
{ | |
if (age > delay) | |
{ | |
action(); | |
Destroy ( gameObject); | |
} | |
} | |
void LateUpdate() | |
{ | |
age += Time.deltaTime; | |
} | |
} |
Specific use of playing a button sound and waiting for the sound to finish, then moving on:
AudioSource.PlayOneShot( ButtonAudioClip);
CallAfterDelay.Create( ButtonAudioClip.length, () => {
UnityEngine.SceneManagement.SceneManager.LoadScene( "MyNextScene");
});
Warning: you may want to disable the button too, otherwise the user can spam the sound.
If you want a CallAfterDelay instance to die at the same time as the rest of your scene, so you don't get null references if you change scenes while one of these is pending, I find the easiest way is to parent the CallAfterDelay instance to the script where you call it from, something like this:
CallAfterDelay.Create( 2.0f, () => {
myButton.interactive = true;
}).transform.SetParent( myButton.transform);
That will set myButton to interactive in 2 seconds, but if you change scenes (or destroy myButton) before then, it avoids firing a pesky missing / destroyed reference.
@kurtdekker I'm curious why you changed from coroutine to the current method?
@omundy @kurtdekker I'm also wondering the same thing. You can have the same behaviour with Coroutines. Callbacks from Update + LateUpdate might be slower too compared to the pure boolean comparison of Coroutine in Update (I suppose it's running in Update, although I'm not sure).
why not coroutine ?
Use CallAfterDelay to cause something to happen later in Unity3D.
For instance:
CallAfterDelay.Create( 2.0f, () => {
Debug.Log( "This is two seconds later.");
});
To make it survive from scene to scene, simply set the returned reference as DontDestroyOnLoad(), like so:
DontDestroyOnLoad( CallAfterDelay.Create( 2.0f, () => {
Debug.Log( "This is two seconds later and survives scene changes.");
}));