- Home /
Make a coroutine run when Time.timeScale = 0;
Hi Guys,
I have been working on a side scroller type game and have alot of my code run in the fixed update method, I currently pause the game using Time.timescale = 0; which works perfectly, however I am adding the in game menu at the moment and would like the buttons to 'slide' onto the screen instead of just appear, I have written the following coroutine to make this happen
function Slide() {
for (var i: int = -10; i < 0; i++) {
ofset = 10 * i;
yield WaitForSeconds(0.1f);
}
ofset = 0;
}
with this as my button code
function gamePausedMenu(windowID:int){
//Restart Button
GUI.Button(Rect(Screen.width/2 - scoreSize/2 - ofset, Screen.height/2 - (scoreSize/3)/2, scoreSize,scoreSize/3),"Restart", leftTop);
//Menu Button
GUI.Button(Rect(Screen.width/2 - scoreSize/2 + ofset, Screen.height/2 + (scoreSize/3), scoreSize,scoreSize/3),"Menu", rightTop);
}
Now this works perfectly however it doesn't run at all while Time.timescale = 0, which I do on pause of course, is there any work around to this, so that I can force my that coroutine to run regardless of timescale?
Thanks in Advance!!
Answer by Bunny83 · Oct 27, 2016 at 10:44 PM
Unity now has a special "WaitForSeconds" called WaitForSecondsRealtime which does the same as WaitForSeconds but is not affected by Time.timeScale.
This update renders the other answers out-of-date.
Just a tip for people who convert existing "WaitForSeconds" to " WaitForSecondsRealtime":
Unlike WaitForSeconds, WaitForSecondsRealtime doesn't work correctly when reused. It won't throw any errors, however it will only yield for 1 frame ins$$anonymous$$d of the specified time. This is common if you're caching one instance for loops ins$$anonymous$$d of generating new copies.
Yes, this is because unlike WaitForSeconds WaitForSecondsRealtime is implemented as "CustomYieldInstruction". While WaitForSeconds is essentially just a container for the desired wait time and the actual waiting logic is implemented in native code, WaitForSecondsRealtime actually contains the state and logic for the waiting. So once the time is expired it will stay expired.
However you can create a "garbage free" solution like this:
public class WaitForSecondsRT : CustomYieldInstruction
{
float m_Time;
public override bool keepWaiting
{
get { return (m_Time -= Time.unscaledDeltaTime) > 0;}
}
public WaitForSecondsRT(float aWaitTime)
{
m_Time = aWaitTime;
}
public WaitForSecondsRT NewTime(float aTime)
{
m_Time = aTime;
return this:
}
}
This can be reused when you use the "NewTime" method.
Of course you have to ensure to never use the same instance in two coroutines at the same time. It would be best practise to create the instance locally inside the coroutine and just use it inside the coroutine.
IEnumerator $$anonymous$$yCoroutine()
{
WaitForSecondsRT wait = new WaitForSecondsRT(1);
while (true)
{
// ...
yield return wait.NewTime(0.5f);
// ...
}
}
Answer by brunopava · Apr 16, 2015 at 12:34 PM
So, in the link below the guy figured it out in an elegant solution that is also re-usable.
public static class CoroutineUtilities
{
public static IEnumerator WaitForRealTime(float delay){
while(true){
float pauseEndTime = Time.realtimeSinceStartup + delay;
while (Time.realtimeSinceStartup < pauseEndTime){
yield return 0;
}
break;
}
}
}
Usabilty:
yield return StartCoroutine(CoroutineUtilities.WaitForRealTime(1));
http://rontavstudio.com/use-coroutines-independent-timescale-unity-3d/
Try to avoid just links, as they tend to break. The trick in the link is to key off of realTimeSinceStartup, which isn't affected by timeScale. Then yield frames (as in an answer above) until RTSSU reaches the desired value.
I added the code to the post. Thanks for the advise, I keep forgeting how anoying is to look for answers and click on broken links.
Answer by Owen-Reynolds · Sep 08, 2014 at 04:58 PM
I think a really cheap, ugly hack might be to change the yield WaitForSeconds to yield return null;
, and take smaller steps:
for(var i : float = -10; i<0; i+=0.3) {
...
yield return null;
}
yield return null;
should always wait for the next frame, regardless of timescale. But that messes up the time -- it used to finish in 10*0.1=1 second. Now it runs in 10 frames (1/6th to 1/3rd of a second?) So just rewrite the loop to take 30 small 1-frame steps.
Your answer
Follow this Question
Related Questions
Question about Coroutines in a Class Function 1 Answer
Unityscript Coroutine Not Running When Called 1 Answer
Cancelling Coroutine when Home button presseddown or returned main menu 1 Answer
What's stopping 'WaitForSeconds' from working? 1 Answer
'pausing' a game to wait for user to select object before proceeding 1 Answer