🎮 UnityDocs

Menú de pausa

Un menú de pausa que congela el juego con Time.timeScale, muestra un panel con botones (reanudar, opciones, salir) y gestiona el cursor. Con las trampas de timeScale que debes conocer.

🍳 RecetaPrincipiante✅ RevisadoUnity 6.0 LTSActualizado 2026-07-15
DificultadConceptual Código Matemáticas
Tiempo📖 Lectura 5 min · ⌨️ Práctica 15 min

El objetivo#

Pulsar Escape y que el juego se congele mostrando un menú con "Reanudar", "Opciones" y "Salir al menú". Sencillo, pero con un par de trampas que conviene conocer.

La receta#

C#
using UnityEngine;
using UnityEngine.SceneManagement;

public class MenuPausa : MonoBehaviour
{
    [SerializeField] private GameObject panelPausa;
    public static bool EnPausa { get; private set; }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            if (EnPausa) Reanudar();
            else Pausar();
        }
    }

    public void Pausar()
    {
        panelPausa.SetActive(true);
        Time.timeScale = 0f;        // congela el tiempo del juego
        EnPausa = true;
        Cursor.lockState = CursorLockMode.None;   // liberar el cursor
        Cursor.visible = true;
    }

    public void Reanudar()
    {
        panelPausa.SetActive(false);
        Time.timeScale = 1f;        // reanuda el tiempo
        EnPausa = false;
    }

    public void SalirAlMenu()
    {
        Time.timeScale = 1f;        // ¡restaurar antes de cambiar de escena!
        SceneManager.LoadScene("MenuPrincipal");
    }
}

Cómo funciona Time.timeScale#

Time.timeScale multiplica el paso del tiempo del juego. A 1 va normal; a 0, el tiempo se detiene: la física se para, las animaciones (que usan tiempo escalado) se congelan y Time.deltaTime vale 0. Es la forma estándar de pausar.

Las trampas de timeScale = 0
  • Update sigue ejecutándose aunque timeScale sea 0 (solo se congela el tiempo, no los scripts). Por eso puedes leer Escape para despausar. Pero FixedUpdate deja de correr (la física está parada).
  • Cualquier cosa que use Time.deltaTime se congela. Si quieres que el menú siga animándose durante la pausa, usa Time.unscaledDeltaTime (ignora el timeScale).
  • Restaura timeScale = 1 antes de cambiar de escena o de salir. Cargar una escena con timeScale a 0 te deja el juego congelado sin que sepas por qué. Es el bug nº1 de los menús de pausa.

Conectar los botones#

Los botones del panel llaman a los métodos públicos (Reanudar, SalirAlMenu) desde su evento On Click, como en botones y eventos. Recuerda que hace falta un EventSystem en la escena para que la UI responda.

Extras habituales#

  • Filtro de audio: baja el volumen o aplica un lowpass al pausar con un snapshot del mixer (ver audio avanzado).
  • Submenú de opciones: volumen, calidad, sensibilidad, dentro del mismo panel.
  • Difuminar el fondo (blur) para resaltar el menú.
  • Bloquear el input del juego: como el juego está congelado, el jugador no se mueve; pero cuida que el clic del menú no dispare también en el juego (comprueba EnPausa en tus scripts de disparo).

Errores frecuentes#

  • No restaurar timeScale = 1 al salir de la escena (juego congelado misteriosamente).
  • Animar el propio menú con Time.deltaTime y que se quede congelado (usa unscaledDeltaTime).
  • Meter lógica de física en la pausa esperando que corra (FixedUpdate no se ejecuta con timeScale 0).
  • Olvidar el EventSystem y que los botones no respondan.
  • Que el clic para pulsar un botón dispare también el arma (comprueba EnPausa).

Resumen#

Pausa con Time.timeScale = 0 y muestra el panel; reanuda con = 1. Ten presente que Update sigue pero FixedUpdate se para, que lo que deba animarse en pausa usa Time.unscaledDeltaTime, y sobre todo restaura timeScale = 1 antes de cambiar de escena. Conecta los botones como en botones y eventos y añade filtro de audio y opciones para el toque final.

Fuentes y para profundizar