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#
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.
Updatesigue ejecutándose aunque timeScale sea 0 (solo se congela el tiempo, no los scripts). Por eso puedes leer Escape para despausar. PeroFixedUpdatedeja de correr (la física está parada).- Cualquier cosa que use
Time.deltaTimese congela. Si quieres que el menú siga animándose durante la pausa, usaTime.unscaledDeltaTime(ignora el timeScale). - Restaura
timeScale = 1antes 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
EnPausaen tus scripts de disparo).
Errores frecuentes#
- No restaurar
timeScale = 1al salir de la escena (juego congelado misteriosamente). - Animar el propio menú con
Time.deltaTimey que se quede congelado (usaunscaledDeltaTime). - Meter lógica de física en la pausa esperando que corra (
FixedUpdateno 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.