How to pause game except for GUI?

I had this script, which smoothly allowed movement of vision, to make it look better overall, I had to restart computer because Windows complained about RAM deficiency, after I restarted my computer, I immediately wanted to start Unity and continue working on my not exactly humble project:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class ShowShop : MonoBehaviour {
    public Camera CameraX;
    public GameObject Shop;

    public float timeing;

    public bool ShopOn = false;

    void Update () {
        if (Input.GetKeyDown(KeyCode.Q)) {
            timeing = 0.0f;
            ShopOn = !ShopOn;
           
            if (ShopOn) {
                CameraX.orthographicSize = Mathf.Lerp (3.5f, 6f, timeing);
                timeing += Time.deltaTime / 10;
                Debug.Log (timeing);
            } else {
                CameraX.orthographicSize = Mathf.Lerp (6f, 3.5f, timeing);
                timeing += Time.deltaTime / 10;
            }
        }

    }
}

Problem is, each time I tell it to set Time.timeScale = 0.0f; it doesn’t necessarily stops all the objects and players from moving. Other objects are stopped from moving, only when they have already arrived at their positions and don’t need to move anymore, they still turn (orbit around their own axis (z)), and player still can move.

My objects rely on transform.position = Vector3.Lerp(); and they turn by

float angle = Mathf.Atan2(dir.y,dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);

Player working movement speed:

using UnityEngine;
using System.Collections;

public class PlayerMovement : MonoBehaviour {
    public float externalMOVMOV = 1;

    void Update() {
       
        Vector3 mousePos = Input.mousePosition;
       
        Vector3 objectPos = Camera.main.WorldToScreenPoint (transform.position);
        mousePos.x = mousePos.x - objectPos.x;
        mousePos.y = mousePos.y - objectPos.y;
       
        float angle = Mathf.Atan2 (mousePos.y, mousePos.x) * Mathf.Rad2Deg;
        transform.rotation = Quaternion.Euler (new Vector3 (0, 0, angle));
       
        if (Input.GetKey (KeyCode.W)) {
            transform.position += transform.right / 10 * externalMOVMOV;
        }
    }
}

How can I make EVERYTHING stop, except for GUI and music?

Setting timeScale to 0 doesn’t necessarily pause everything. It just makes anything that is dependent on timeScale slope out to zero.

If any movement is not based on timeScale, then you’re still going to get movement.

And inputs and the sort still function.

Timescale does not slow down the update process. Update still occurs as many times per second as the framerate.

So you’ll need to do more than just set the timeScale to 0.

Furthermore, while timeScale is 0, if your HUD is dependent on it, it too will freeze. So you’ll need to make it dependent on a different delta. Like Time.unscaledDeltaTime and Time.unscaledTime.

I’ll show you what I do to ‘pause’ my game if you want. It’s long, so I’ma spoiler it:

First off my game has ‘states’, one of which is GamePlayState, another is GamePausedState, these are part of a state machine on a GameObject in the level.

In the GamePlayState during Update I check if the pause button is pressed, if it is pressed I call ‘Pause’ on the state machine:

        public void Pause()
        {
            if (this.Paused) return;

            _stateManager.ChangeState<GamePausedState>();
        }

This changes into my GamePausedState if we aren’t already in that state.

And this is what that does:

using UnityEngine;
using System.Collections.Generic;
using System.Linq;

using com.spacepuppy;
using com.spacepuppy.Audio;
using com.spacepuppy.Utils;

using com.apoc.Ui;

namespace com.apoc.Scenes.Levels
{

    public class GamePausedState : AbstractLevelState
    {
       
        #region Fields

        #endregion

        #region Properties

        #endregion

        #region Methods

        #endregion

        #region AbstractLevelState Abstract Overrides

        public override void OnEnterState(AbstractLevelState lastState)
        {
            SPTime.Normal.Paused = true;
            AudioManager.Global.Pause();
            Notification.PostNotification<GamePausedNotification>(this.Level, new GamePausedNotification(true), false);

            if (this.Level.HUD != null) this.Level.HUD.StatsVisible = true;
        }

        public override void OnExitState(AbstractLevelState nextState)
        {
            SPTime.Normal.Paused = false;
            AudioManager.Global.UnPause();
            Notification.PostNotification<GamePausedNotification>(this.Level, new GamePausedNotification(false), false);
        }

        public override void UpdateState()
        {
            var inputDevice = Game.InputManager.FirstOrDefault() as ApocPlayerInputDevice;
            if (inputDevice == null) return;
            var input = inputDevice.GetCurrentState();

            if (input.Pause == spacepuppy.Ui.ButtonState.Down)
            {
                this.Level.ReturnToGamePlay();
            }
        }

        #endregion


        private void OnGUI()
        {
            if (!this.IsActive) return;

            var c = Color.black;
            c.a = 0.5f;
            GUI.color = c;
            GUI.depth = int.MinValue;
            GUI.DrawTexture(new Rect(0f, 0f, Screen.width, Screen.height), SPAssets.WhiteTexture);
        }

    }
}

You may notice I use a weird class called SPTime… I don’t like the unity Time class and wrote a wrapper around it so I can give Time an object identity. This is nice so I can pass references to which kind of time I want to use around. This is really great for things like my tweener and the sort where I can choose if the tween updates by time, unscaledtime, or even a custom scaled time. My HUD is actually dependent on one of these ‘custom’ scaled time objects.

You can find it here:
spacepuppy-unity-framework/SpacepuppyBase/SPTime.cs at master · lordofduct/spacepuppy-unity-framework · GitHub

So on enter of the state we pause ‘normal’ time. This is basically setting Time.timeScale to 0 (look in SPTime to see).

I pause my AudioManager.

And I then dispatch a notification into the scene telling the world that we just paused the game. This is captured by any entities that may need to stall out their processes if the game pauses. Inside my entity class (which all mobs and the player get) I have the notification consumed and it ‘stalls’ my entity:

        private void OnGamePaused(object sender, GamePausedNotification n)
        {
            this.StallEntity((n.Paused) ? StallMode.Paused : StallMode.Active);
        }

        /// <summary>
        /// Put the entity into a state where it's not considered active.
        /// </summary>
        /// <param name="active"></param>
        public void StallEntity(StallMode mode)
        {
            _stallState = mode;
            switch(_stallState)
            {
                case StallMode.Active:
                    if (this.AIContainer != null) this.AIContainer.SetActive(true);
                    if (this.CombatMotorContainer != null) this.CombatMotorContainer.SetActive(true);
                    if (this.MobileMotorContainer != null) this.MobileMotorContainer.SetActive(true);
                    if (this.MovementController != null) this.MovementController.Pause(false);
                    //if (this.AttributesContainer != null) this.AttributesContainer.SetActive(true);
                    if (this.EventHitBoxContainer != null) this.EventHitBoxContainer.SetActive(true);
                    break;
                case StallMode.Paused:
                    if (this.AIContainer != null) this.AIContainer.SetActive(false);
                    if (this.CombatMotorContainer != null) this.CombatMotorContainer.SetActive(false);
                    if (this.MobileMotorContainer != null) this.MobileMotorContainer.SetActive(false);
                    if (this.MovementController != null) this.MovementController.Pause(true);
                    //if (this.AttributesContainer != null) this.AttributesContainer.SetActive(true);
                    if (this.EventHitBoxContainer != null) this.EventHitBoxContainer.SetActive(false);
                    break;
                case StallMode.Animating:
                    if (this.AIContainer != null) this.AIContainer.SetActive(false);
                    if (this.CombatMotorContainer != null) this.CombatMotorContainer.SetActive(false);
                    if (this.MobileMotorContainer != null) this.MobileMotorContainer.SetActive(false);
                    if (this.MovementController != null) this.MovementController.Pause(true);
                    //if (this.AttributesContainer != null) this.AttributesContainer.SetActive(true);
                    if (this.EventHitBoxContainer != null) this.EventHitBoxContainer.SetActive(true);
                    break;
                case StallMode.Dead:
                    if (this.AIContainer != null) this.AIContainer.SetActive(false);
                    if (this.CombatMotorContainer != null) this.CombatMotorContainer.SetActive(false);
                    if (this.MobileMotorContainer != null) this.MobileMotorContainer.SetActive(true);
                    if (this.MovementController != null) this.MovementController.Pause(true);
                    //if (this.AttributesContainer != null) this.AttributesContainer.SetActive(true);
                    if (this.EventHitBoxContainer != null) this.EventHitBoxContainer.SetActive(false);
                    break;
            }
        }

Depending the mode I turn on or off gameobjects that handle certain aspects of the entity. Those containers correspond to the gameobjects that are a child of my root entity gameobject. You can see this in this image:

2 Likes