How to PAUSE a Game | Unity Tutorial
Вставка
- Опубліковано 2 жов 2024
- Time.timeScale was not my cup of tea. Make a custom class to gain full control over how each object will pause. Keep i mind that this is one way of pausing, you can apply the same idea in different ways.
I did a follow up video talking more about timeScale: • I was wrong about Time...
★ Join the Kingdom:
/ discord
► The GameDev Website: gamedev.lu
········································
● X: x.com/GameDevLu
● Instagram: / gamedev.lu
Thanks all for the great comments! This made me reconsider the usage of timeScale. I’ll post an additional explainer video about this subject.
You're replying to other comments saying 'what about interactive menus, animators, particles, music, etc, that will stop functioning when timescale is set to 0?' But there is a solution built right into Unity that is for this exact problem, it's called unscaled time. Anything using Time.unscaledDeltaTime will continue to run as though the timescale were set to 1, even when it's set to 0. There are even toggles on the particle system and animator components to use unscaled time to ensure they keep working when the timescale is 0. For audio sources, they already play independently of the timescale, so if they're not working properly when timescale is set to 0, then it means that in whatever code is calling your play/stop/whatever functions you need to be using unscaledDeltaTime instead of normal deltaTime.
That’s true. And for simple use case this is fine. Personally, for larger projects, or when you start including more third-party libraries you will reach the point where you need custom behaviours when the pause event kicks in. Really not a fan of mixing deltaTime along with unscaledDeltaTime.
Working around the issues of timescale seems simpler than designing around this.
In some simple cases yes. Once you need an interactive menu, inventory UI and handle music changes, timescale becomes a limitation.
@@this-is-gamedev and I will go for timescale. If I happen to be wrong with that, I will post that here and you may say "I told ya" ;-)
All good! Whatever works, works. I just present more ways to do something :)
for animations and audio to be played while the timescale is set to 0, just set the animator and the ausiosource update mode to unscaled time
If you're already using an event system (like you should in MANY games) then all you have to do is make a new class that inherits from monoBehavior, change that 1 thing in your pauseable scripts, change your timescale line to instead freeze that class, and it works. This gives you way more functionality while paused.
Thanks i had no clue wat the time scale code was thanks for puting it at the begining. very easy to use.
(for anyone wondering)
Time.timeScale = 0 //pause the game
Time.timeScale = 1 //unpause or play the game
Finally a decent video about the topic, following Brackeys and the likes tutorials brings you nowhere and keeps you in tutorial hell forever.
We in Unreal Blueprints only have a Node called "Pause Game". No need to add complicated stuff 😎
Spoiled unreal devs 😅
Other people have already said this; but I'd strongly advocate that Time.timeScale = 0 is the right way to pausing Unity in most situations.
This is because it will pause all things related to time, e.g. particle systems, physics as well as your mono behaviour code if it uses Time.deltaTime; and coroutine work as well. For example, in the video, you can see the smoke still flying because the time scale is unchanged; but it would pause if using the time scale method.
Unity has lots of ways to have things not be impacted by time, e.g. you can change a flag in the particle systems to use unscaled time (same for the animator); and if you want a specific game object not to be paused, just use Time.unscaledDeltaTime instead of Time.deltaTime, and it will still work. Equally, Coroutines have a WaitForSecondsRealtime option if you don't want to have it paused.
Where pausing via time scale becomes messy is when you also want to have the ability to do slow motion; or have multiple objects that can pause/unpause the game. In that case, having a single TimeManager class that handles time can make this cleaner.
Honestly, I can't imagine a situation in which "timescale = 0" is such a bad practice, that we need to do so much work for pausing every coroutine, particle system, animator, etc...
Unless when some script should stop at one pause, and should not stop at another.
But again, can't imagine an ordinary game with 2 mechanically different pauses.
As soon as your pause menu becomes slightly more complex, where other animators, particle effects or other components affected by timescale need to keep running, is the timeScale approach annoying to use.
Pausing rigid body velocity might be a nightmare without timescale
@@this-is-gamedev I understand that this approach is more flexible and controllable. But I have a strong feeling that this is not about “noob and pro” or “good and bad”, but about necessity.
Like, ok, I need a scenario where during a pause some objects stop, while others, such as particle systems, are slowed down using a timescale. But how often is this really needed? I don't think it's often enough, to do all this extra code in each project
Fair enough! Didn’t mean to degrade other approaches. It is good to have those discussions and code is always refactorable :D . I’ll post an update in the next days covering Time.timeScale in more detail and the differences with enabling/disabling monobehaviours.
You can use unscaledDeltaTime for all that.@@this-is-gamedev
I really feel like this is an extremely bad solution... The beauty of setting the time scale to 0 is all game behaviors that are "time driven" will result in 0 which should be handled as paused.
The other thing is when the game is paused I don't have to be concerned that my none time driven systems will stop because the update and fixed update loops will continue working as intended. And if I happen to need to stop input from the update loop then in that case I will specify add this Mono Behavior to be disabled as part of pausing the game. Instead of having to go through each and every object and mark it as "pausable"... This will just result in a lot of unhandled objects and states which will take more time debugging and fixing to work.
And when it comes to animations and UI it will be as simple as setting the animator from "Normal" to "Unscaled Time" and in code just switching from "Time.deltaTime" to "Time.unscaledDeltaTime"
It's much easier to work around limitations of time scale rather than working around the limitations of "not having an game loop while paused"
Though you are not entirely wrong. This could be handled better. Instead of pausing the game from where you need to pause with time scale, try to always have one place that is changing the time scale, your "PauseMenu/PauseManager" and the pausing will only be triggered from there. And also there should be an event for "OnPauseStateChanged(bool/PauseState)" that you will hook the functionality you need for example disable the kono behaviors that you want to stop. And then finally for stuff that cause problems because the time scale is 0 you just replace the "Time.deltaTime" with "Time.unscaledDeltaTime" and switch your animators from "Normal" to"UnscaledTime" that s should minimize the errors caused by this if there is any... But the major thing is just always make sure you're changing the time scale from 1 and only 1 place. So if any issues happen you know from where it caused, of course this is not an absolute rule but it's just something to avoid
Yea, I agree, this is an extremely large, disruptive hammer that requires maintenance on every single thing you design for a relatively small nail. Committing to a base class of 'MonoBehaviourPausable' on everything in your world is weird and will become frustratingly restrictive, not to mention you're forcing a lot of garbage collection on what will ultimately become a really massive delegate object by adding and removing delegates all the time. I'm working on a game where different characters can be moving in different time scales due to time warping in the world, and my solution isn't half as complex as OP's is for just pausing. No offence man! I think you went into super-programmer mode and overengineered something for which there are much simpler, more targeted solutions.
Naah, I'll stick with timeScale
Interesante
The only problem I have with time.timescale is that when i pause the game my frames rise to infinity
You can limit the framerate with Application.targetFrameRate
Your solution only handles pausing MonoBehaviours. What about physics?
This can be done in PostPause, PostResume. You switch rigidbodies to kinematic or even better you change the Physics.simulationMode to Script and call Physics.Simulate manually.
I know this is a lot more work, but Pause != Stop. Lots of systems should still run while just the gameplay is paused.
finally! this is for me! thank you for showing the another way!
Hello, Idk if anyone can help me but im making a game and currently my pause menu pauses the game but not the camera and i cant have click in any buttons
Difficult to say. But I did another video talking in details about the TimeScale.
just crate script
=========
void OnEnable()
{
Time.timeScale = 0;
AnotherDisableComp(true);
}
void OnDisable()
{
Time.timeScale = 1;
AnotherDisableComp(false);
}
===========
and attached to UI Pause Menu Panel
done, you made Pause Function just be enable and disable one object (UI Pause Menu Panel)
How about the music? 🎧 i would like it to fade away to another soundtrack during pause ? ^^ timescale stops the music completely
@@this-is-gamedev you can also add keyboard event script to that pause menu panel,
example script
=======
[SerializationField] KeyCode key;
public UnityEvent onPress;
void Update()
{
if (Input.GetKeyDown(key))
{
onPress.Invoke();
}
}
=======
and attached it to Null Object and Your Pause Panel
in Null Objek, set key to Escepe, and attach event to enable Pause Panel also disable self
and for Pause Panel, set it same, but reverse
so Pause Input will not overlaps with other same key Input
@@this-is-gamedev for make sound fade, you just need add your AudioMixer fade function to AnotherDisableComp ()
Edit: it's should be the first Reply Comment, but idk why after I refresh, my last comment gone
meanwhile unreal engine:
PlayerController->SetPause(true)
done
sure buddy :D
meanwhile in unreal no round fillable slider by default
Lol as a Unreal Developer I can confirm that this is true 🤓
In unity it's just timeScale = 0, this guy is just evangelizing a bad design, (sorry, dude!)
Systems that you need to keep going even when paused can just use unscaledTime.
In Unreal the equivalent to what he's done would be making every blueprint or C++ class implement an IPausable interfaces and broadcasting messages to them every time a button is pressed rather than just calling PlayerController->SetPause(true)
@@jlr3739 the default pause system in unreal is exactly what is shown in the video, you can choose the things you want to be paused, meanwhile timeScale = 0 is the lazy way which can be bad for some projects