Among all the shiny new features, there is a tiny one line in the Unity 5.3 release notes for a feature that I found useful and I think you will too. Custom coroutines, namely the new CustomYieldInstruction class, mean that you can now add your own coroutine yield operations in a very simple way. So let’s take a look at a real world example.
A real world example — A bugfix
I was recently investigating a bug in the UI Dropdown component, a Unity 5.2 feature. When Time.timescale was set to 0, the Dropdown component would only work once, then it would not reappear until timescale was set back to a non-zero value.
After a bit of debugging, we found out that the problem is in the Show function.
Once shown, the m_Dropdown component is minimised and then destroyed. Well, it should be destroyed, but when the timescale is 0, this is not happening.
Take a look at the destroy function and see if you can spot the problem.
The title of this article may have given it away, but WaitForSeconds is the answer. WaitForSeconds uses scaled time. This means that if you tell WaitForSeconds to wait for 1 second and the timescale is 0.5, then you actually wait for 2 seconds (1 / 0.5 = 2). So using WaitForSeconds with a timescale of 0 means that you wait indefinitely (until the timescale is not 0). The Dropdown was never being destroyed after its first use, because we would get held up by the WaitForSeconds yield instruction.
We need to wait using unscaled time; the most elegant approach here is to add a new yield operation, a WaitForSecondsRealtime class. Clearly, if our own developers do not realise WaitForSeconds uses scaled time, then we need to address this. WaitForSecondsRealtime should help reinforce this message. We also need to update the docs for WaitForSeconds (we never mention scaled time!).
This is how I discovered the CustomYieldInstruction, recently added for creating new yield operations.
Adding a new yield operation is very simple, here is the solution to our problem.
Any custom yield operation needs to override the keepWaiting property and once we want the yield operation to continue, we just pass back false.
Here is how our fix now looks:
In our example, we grab the real time and just test against it each check. It doesn’t get much simpler than that — oh wait, it does, because we now also have the WaitUntil and WaitWhile yield instructions. With these, we can provide a delegate to be called for our yield instruction test.
Here is an alternative way to solve our problem, assuming we wanted a 5 second delay.
So, a simple feature, but with a lot of potential. I guess the lesson learned here is: Remember to read the release notes, you never know what useful features you might find! If you like the custom coroutines, you should take a look at UnityEvents, another favourite feature of mine that you may have missed.