this isn’t really a question but a useful trick I thought of sharing for invoking functions after some delay.
Unity only allows you (afaik) to invoke functions by name with some delay, which prevents passing arguments or using lambdas. Previously, if you wanted to do that, you’d have to either create and name a new function or a new coroutine with the same boiler-plate code. With these snippets, it’s possible to invoke a function or lambda with the same syntax and no boiler code. (the this syntax is needed for the extension function).
I saw there are some paid assets to achieve this but seems overkill for only two functions.
Well, I created the CoroutineHelper (archive.org backup) years ago, long before we had custom yield instructions and long before we could properly stop coroutines. It can achieve the same thing, just in a more general way and also provides some methods for common tasks. Apart from that I came across several free solutions over the years. My solution uses a singleton instance so you can use “Run.After” from almost everywhere.
You can call CancelInvoke without parametes, but that’ll cancel all invoke-calls in the script. If you just have one anyways, you can just do that, but if you have multiple it’s not a good idea.
Besides that you can only cancel a specific invoke-call if you give a method-name as the parameter. And otherwise you could consider using an IEnumerator, which’ coroutine you can store in a variable and then cancel: Unity - Scripting API: MonoBehaviour.StopCoroutine
Unfortunately, no. This would not work. You either have to store the Coroutine object that is returned by StartCoroutine and use that in StopCoroutine, or store the actual IEnumerator object that your coroutine creates and use that in StopCoroutine. Doing StopCoroutine(InvokeRoutine()) won’t do anything as you would create a new IEnumerator that Unity doesn’t even know yet and does nothing as there’s no coroutine running with that specific IEnumerator instance.
StopCoroutine(nameof(InvokeRoutine)) should still work.
StopCoroutine(InvokeRoutine()) MIGHT work? According to the Summary it should stop the first running routine on the object BY NAME.
Nope and nope The string based version are essentially historical left overs. StopCoroutine with a string only works when you started a coroutine using StartCoroutine that takes a string. When you used the IEnumerator version, the StartCoroutine method has no idea what the name of the generator method is. When you do
Calling your “coroutine” method will just create a new state machine object which is returned by your method. Nothing else happens here. You then pass this object to StartCoroutine which will store that object internally and the coroutine scheduler will start “iterating” this object. It has no connection to the method that generated this object. However that “iterator” object is exactly what you would need to stop the coroutine. Though it has to be the exact object, the actual statemachine.
I would not recommend to use the string version of StartCoroutine. You can’t pass arguments to the actual coroutine and the string binding is slow and error prone (of course the new nameof operator would minimize those errors).
The best solution, if you really want to stop a coroutine from the outside, is to store the Coroutine object that StartCoroutine returns. This is usually easier than storing the IEnumerator object.
Though it’s generally not recommended to stop coroutines from the outside. While it’s not possible to have actual race conditions with coroutines in Unity (since they run synchronously), it’s still an external trigger that could exit the coroutine at any yield statement. This makes it difficult to reason about the code and such a coroutine could not rely on some clean up code at the end, since it could possibly never reach it. It’s generally better to let the coroutine itself finish gracefully.
Of course as you probably know, starting and stopping (or ending) coroutines is kinda expensive. Coroutines are statemachine objects which require a heap allocation. So if possible coroutines should just keep on running. You could trap a coroutine in a while loop with a yield return null in it to essentially suspend it until an external condition becomes true / false again. Now that’s of course not a general rule. Coroutines can be used in many different ways and if not overused, the allocations usually don’t matter. It’s just something to keep in mind.
ps: As I said, coroutines are actually statemachines. The yield keyword in C# just allows you to easily construct such a state machine with some compiler wizardry. I’ve written a coroutine crash course (github backup) which goes into more details how it works behind the scenes. Though my point here is that you can actually just create such a class yourself. So that class would not have a “generator method”. So method or class names simply don’t matter to the coroutine scheduler with the exception of the string version which has several limitations.