Hello, Is there a way to check if a coroutine is finished before continuing the code? I want to: - Run coroutine; - Wait for it to finish; - Destroy gameObject; Can anybody help me? Thanks!
Do you have the coroutine currently working? here is a sample if you don't Code (CSharp): using UnityEngine; using System.Collections; public class WaitForSecondsExample : MonoBehaviour { void Start() { StartCoroutine(Example()); } IEnumerator Example() { print(Time.time); yield return new WaitForSeconds(5); print(Time.time); Destroy(this.gameObject); } }
I know I could just destroy the gameObject at the end of the coroutine, but for my case it would be better to check if the started coroutine is already finished and then, if it is, destroy it. This is because I have a parent Powerup class that has an abstract Effect() coroutine, and all its children override it to do the desired effect. So instead of writing Destroy(gameObject) in all of the children, I wanted to just check if the coroutine is finished, destroy the gameObject from the parent, which is the one that starts the coroutine as well... The children just overrides the effect, but the parent starts it. Here is my code in case it got confusing: Parent: Code (CSharp): protected override void OnTriggerStay(Collider collider) { if (collider.CompareTag("Player") && collider.GetComponent<PlayerController>().isAlive) { // Some code... PlayerController playerController = collider.gameObject.GetComponent<PlayerController>(); StartCoroutine(Effect(playerController)); // If (Coroutine is finished) // Destroy(gameObject); } } public abstract IEnumerator Effect(PlayerController player); Child (One of them): Code (CSharp): [SerializeField] float duration = 7f; public override IEnumerator Effect(PlayerController player) { player.isInvincible = true; yield return new WaitForSeconds(duration); player.isInvincible = false; yield break; } Can anybody tell me if there's a better way to do this instead of writing Destroy(gameObject) in every child? Thanks!
In the parent class, you could have another coroutine that yields on the effect coroutine (to finish). From there, you could then destroy the game object? Edit: I notice your code example starts a coroutine during ontriggerstay. That will start many coroutines; that is probably not what you want?
On trigger stay means what it says. As long as it "stays inside", do something. You want OnTriggerEnter probably. As far as destroying an object from the parent, just pass in a callback method which gets called at the end of the coroutine. Then, when it ends, it can call the method on it's parent, passing itself as a param and says to destroy it. But, really, if that is all it does, just destroying in the child is perfectly fine. Otherwise, I don't understand why you hesitate to add a line of code to the scripts. Coroutines, at least to my best knowledge, don't have a way to inform you they are done. So while you can implement your own, they will still take extra code.
Thanks for all the replies! The callback method thing makes sense, but I ended up just destroying the gameobject at the end of each coroutine. Also the reason I used OnTriggerStay() is because sometimes the player can spawn in a powerup, in which case the powerup should be collected instantly instead of requiring the player to leave the trigger and enter it again. Here is my final code if someone is interested: Parent: Code (CSharp): protected override void OnTriggerStay(Collider collider) { if (collider.CompareTag("Player") && collider.GetComponent<PlayerController>().isAlive) { PlayerController playerController = collider.gameObject.GetComponent<PlayerController>(); // Some code for disabling components such as MeshRenderers, Colliders, etc... StartCoroutine(Effect(playerController)); } } public abstract IEnumerator Effect(PlayerController player); Child: Code (CSharp): [SerializeField] float duration = 7f; public override IEnumerator Effect(PlayerController player) { // Some code to do the effect yield return new WaitForSeconds(duration); // Some code to undo the effect Destroy(gameObject); yield break; }
It's a really useful thing to just create a new GameObject even and attach the script to it with 'new GameObject()' then gameObject.AddComponent<CoroutineClass>().