Gamasutra: The Art & Business of Making Gamesspacer
arrowPress Releases
July 29, 2014
PR Newswire
View All
View All     Submit Event





If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 
Lovers in a Dangerous Spacetime DevLog #9: Pausing Without Pausing
by Adam Winkels on 03/26/14 02:04:00 pm   Expert Blogs   Featured Blogs

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

tunnel_unlock

The simplest approach to pausing your game in Unity is to set Time.timeScale = 0. While the time scale is 0, Update methods in your scripts will still called, but Time.deltaTime will always return 0. This works well if you want to pause all on-screen action, but it is severely limiting if you need animated menus or overlays, since Time.timeScale = 0 also pauses animations and particle systems.

We first encountered this limitation when we were trying to implement a world map in Lovers in a Dangerous Spacetime. When the player enters the ship's map station, we display a overlay of the current level. Since the map obstructs the ship and, as such, inhibits gameplay, we needed to pause the game while the display is visible. However, a completely static map screen would make it difficult to convey information (and also look pretty dull). In order to achieve our goal we needed a separate way to track how much time has elapsed since the last update loop.

It turns out that Time.realtimeSinceStartup is the ideal mechanism for this. As its name implies, Time.realtimeSinceStartup uses the system clock to track how much time has elapsed since the game was started, independent of any time scale manipulation you may be doing. By tracking the previous update's Time.realtimeSinceStartup, we can calculate a good approximation of the delta time since the last frame:

Click to view Gist

This script on its own is not enough, however, especially since we want to use Unity's Animation component to drive our dynamic map elements. To allow this, we created a subclass of TimeScaleIndependentUpdate that manually "pumps" the animation:

Click to view Gist

By using AnimationState's normalizedTime property and our calculated delta time, we scrub through the animation in each Update. Now all we need to do is attach this script to the GameObject we want to animate while Time.timeScale = 0:

tsia-attached
timescale_map2

As you can see above, the game action is paused when the map appears, but the icons on the map are still animating. Particle systems can also animate while the game is paused. ParticleSystem contains a handy Simulate method which, similar to Animation, allows us to manually pump the particle animation. All that's needed is a simple subclass of TimeScaleIndependentUpdate:

Click to view Gist

We can combine these three scripts to create fairly complex sequences. In Lovers, once the player has collected enough friends to unlock a warp tunnel, we play a little cutscene while Time.timeScale = 0:

This sequence relies heavily on the TimeScaleIndependentWaitForSeconds method of TimeScaleIndependentUpdate, which approximates Unity's built-in WaitForSeconds method and is extremely useful for creating coroutines.

Original post

// Adam Winkels (@winkels) is a co-founder of Asteroid Base.


Related Jobs

Sony Online Entertainment, San Diego
Sony Online Entertainment, San Diego — San Diego, California, United States
[07.29.14]

Intermediate and Senior Database Tools Programmers
2K
2K — Novato, California, United States
[07.29.14]

Senior Engine Programmer
Turbine Inc.
Turbine Inc. — Needham, Massachusetts, United States
[07.29.14]

Cloud Solution Architect
2K
2K — Novato, California, United States
[07.29.14]

Senior Animation Engineer






Comments


Dave Siegel
profile image
Just logged in to thank you for writing this series. I have been learning the ropes with Unity for a little while now, and these posts have been really nice for grasping some useful stuff I don't see much of on the dev Wiki. Thanks!

Luke Mildenhall-Ward
profile image
I created the same code for my game because I wanted to use iTween in my menus. For those in a similar situation—and who aren't as dumb as myself—you'll probably already know that iTween already has this functionality built-in via the 'ignoreTimescale' property. D'oh!

Emeka Enubuzor
profile image
These dev blogs have been increasingly becoming my favorite part of Gamasutra. I really love these ideas and solutions that the Spacetime team come up with in unity. It's very informative and inspirational.

Keep up the good work everyone!

Marvin Papin
profile image
Same for me even if in that case I already use that system.

Brian Schaeflein
profile image
Ditto. Whenever I see one of these, I read it immediately, then bookmark it.

Shay Pierce
profile image
This is one of the most useful game dev blog posts I've ever read on Gamasutra. This is a problem that's not obvious from the outside, but is a big tricky question once you actually think it through. Great solution too - I will definitely use this trick in some future project!

It would be nice if there were some way to, each frame:
A. set timeScale to 1
B. call the Update() function on a specific subset of Components you want updated in a non-paused way
C. set timeScale back to 0

...But I suspect that doing B is impossible, since the game engine handles calling Update(), and I imagine that a lot of processing happens using methods other than Update (FixedUpdate comes to mind, maybe there are others too?)

Onome Igharoro
profile image
Great post! Think I'll be re-working a couple of parts in our game now :)

Todd Boyd
profile image
Awesome to see code posted on Gamasutra again. Love the devblog posts.

Lior Tal
profile image
Why does setting timeScale = 0 pauses the game? what if i have some functionality that does not rely on the time delta?

David Cummins
profile image
This approach is so familiar that I had to sign up just so I could comment on it. I agree that it works, and is one of very few ways of getting the job done, but it does have one horrible caveat which caused us a 5 day QA/dev cycle to fix.

I was working on porting a suite of mini-games. One of the mini-games had a freeze bug which we just couldn't replicate. To cut a long painful story short, it was the pause menu animation pump. Because the delta time was calculated from the floating point real time since startup, after the game had been running for around 40 minutes there was the risk of a zero delta time due to loss of floating point precision. A delta time of zero caused infinite looping in the third party animation pump. The chance of failure increased as time passed. We did a workaround to fix it, but if you looked carefully the animation speed wavered more as time went by.

I'm not saying not to use this approach, but be very very sure your code is bulletproof.

Adam Winkels
profile image
That is a very good point that I had not seriously considered. Anecdotally, we were running the game for 8 hours at a time at GDC this year and the animations were running fine, so I'm surprised that you experienced issues after only 40 minutes, though the problem could be platform-dependent.

If this does become an issue, using Ticks from System.DateTime to calculate deltaTime instead of realTimeSinceStartup may be a solution.

Thanks for the input!

David Cummins
profile image
No problem. It wasn't 100% reproducible, or even 30%. It's a combination of time, framerate and poor luck. Disney's testers are just that thorough!

I can't say that I read through your code in detail, so it may simply be that your code is better designed than the 3rd party code we were dealing with. I thought it was a caveat worth mentioning, because I'd rather nobody go through the pain that we did. ;)


none
 
Comment: