Tutorial de Godot – Parte 16: Menú de pausa. Reiniciar y salir del juego

Algo que forma parte de cualquier GUI de juegos es el menu donde aparecen las opciones de pausa, salir del juego y reiniciar partida. Con este tutorial aprenderas a crear estos menus, y podras crear una pausa en godot sin mayor dificultad

El menú de pausa creado en godot que haremos para nuestro juego estará formado por 3 elementos de menú:

  • Reanudar juego
  • Renunciar
  • Reinicia el juego

El jugador abrirá el menú presionando la tecla de escape o el botón de inicio/opciones en el joypad, luego puede navegar con las teclas de flecha o D-Pad y seleccionar el elemento resaltado presionando la barra espaciadora o el botón de ataque del joypad.

La idea es que el jugador acceda al menú del juego pulsando la tecla escape, el botón de inicio/opciones del mando y posteriormente con las flechas del mando y los cursos del teclado se mueva por las opciones correspondientes.

Dibujar la GUI del menú

El resultado final que queremos conseguir es este:

¡Veamos cómo hacerlo!

Todo empieza agregando un nodo popup en el canvasLayer y lo llamamos menuPopup. Pulsando el icono del ojo este menú se puede hacer visible o invisible

Dado que el menú debe funcionar cuando el juego está en pausa, establezca la propiedad Pausar → Modo de MenuPopup en Procesar . Además, establezca Exclusivo en Activado para evitar que la ventana emergente se cierre en respuesta a los eventos del mouse.

Agregue un nodo ColorRect a MenuPopup . Establezca Rect → Posición en (60, 40) y Rect → Tamaño en (200, 100), luego configure la propiedad Color en (80,80,80,255).

Agregue otro ColorRect a MenuPopup y cámbiele el nombre a Resume . Establezca Rect → Posición en (70, 50) y Rect → Tamaño en (180, 20). Ahora agregue una etiqueta para reanudar . En la propiedad Fuente personalizada , cargue la fuente Font.tres (la encontrará en la carpeta Fuentes ) y en Colores personalizados , configure el Color de fuente en negro. Escriba REANUDAR JUEGO en la propiedad Texto de la etiqueta, luego establezca Alinear y Valign en Centro . Finalmente, establezcaRect → Tamaño a (180, 20).

Ahora, duplique Resume dos veces. Cambie el nombre de una copia a Reiniciar y la otra a Salir . Terminará con esta estructura de nodo para MenuPopup :

Establece Restart ‘s Rect → Position en (70, 80), luego cambia el texto de su etiqueta a RESTART GAME . Seleccione el nodo Salir y establezca su Rect → Posición en (70, 110). Finalmente, cambia el texto de su etiqueta a SALIR .

Guión de menú

Adjunte un nuevo script a MenuPopup y guárdelo como MenuPopup.gd en la carpeta GUI .

Primero, agreguemos algunas variables:

onready var player = get_node("/root/Root/Player")
var already_paused
var selected_menu

La variable jugador contendrá una referencia al nodo Jugador . Para inicializarlo, usamos una nueva palabra clave: onready . La palabra clave onready difiere la inicialización de una variable hasta que se llama a _ready() . Esa sola línea es una forma compacta de escribir el siguiente código:

var player

func _ready():
	player = get_node("/root/Root/Player")

La variable before_paused se usa para almacenar si el juego ya estaba en pausa cuando se invocó el menú. Si es así, no tenemos que despausar el juego al salir del menú (por ejemplo, el juego ya está en pausa si abrimos el menú durante una conversación con un NPC).

La última variable, selected_menu , almacena el elemento de menú resaltado actualmente.

Antes de escribir el código que maneja la entrada del menú, escribamos una función que establezca el color de los elementos del menú, para resaltar el actual:

func change_menu_color():
	$Resume.color = Color.gray
	$Restart.color = Color.gray
	$Quit.color = Color.gray
	
	match selected_menu:
		0:
			$Resume.color = Color.greenyellow
		1:
			$Restart.color = Color.greenyellow
		2:
			$Quit.color = Color.greenyellow

Las tres primeras líneas establecen los elementos del menú en el color predeterminado. Luego, la declaración de coincidencia se usa para verificar qué elemento está resaltado para cambiar su color.

Para manejar la entrada, lo primero que debemos hacer es crear una nueva acción de entrada para abrir el menú. Haga clic en el menú Proyecto → Configuración del proyecto y vaya a la pestaña Mapa de entrada . Aquí, debe crear una nueva acción llamada menú , a la que le asignará dos eventos: la tecla Escape y el evento Dispositivo 0, Botón 11 del joypad (Inicio en Xbox, Opciones en PlayStation).

Ahora podemos empezar a escribir la estructura básica de la función _input():

func _input(event):
	if not visible:
		if Input.is_action_just_pressed("menu"):
			pass #TODO
	else:
		if Input.is_action_just_pressed("ui_down"):
			pass #TODO
		elif Input.is_action_just_pressed("ui_up"):
			pass #TODO
		elif Input.is_action_just_pressed("attack"):
			match selected_menu:
				0:
					pass #TODO
				1:
					pass #TODO
				2:
					pass #TODO

La función maneja dos estados posibles:

  • el menú está oculto : si el jugador presiona el botón de menú , queremos pausar el juego y mostrar el menú.
  • el menú es visible : queremos navegar por el menú con las teclas de flecha arriba y abajo y seleccionar el elemento resaltado con la barra espaciadora.

Comencemos desde el primer estado. Agregue este código para cuando el menú esté oculto y el jugador abra el menú:

# Pause game
get_tree().paused = true
# Reset the popup
selected_menu = 0
change_menu_color()
# Show popup
player.set_process_input(false)
popup()

Este código hace lo siguiente:

  • pausa el juego configurando la propiedad de pausa del árbol del juego en verdadero
  • restablecer el menú eligiendo el primer elemento y llamando a la función change_menu_color()
  • deshabilita el procesamiento de entrada para Player
  • finalmente, muestra el menú llamando a la función popup() .

Cuando el menú está visible, tenemos que manejar los eventos de entrada ui_up y ui_down . Para ui_down , ingrese este código:

selected_menu = (selected_menu + 1) % 3;
change_menu_color()

Para seleccionar el siguiente elemento del menú, debe aumentar el valor de la variable selected_menu . Esto funciona hasta que el elemento seleccionado es el último: en ese caso, selected_menu es 2 y aumentando iría al elemento 3, que no existe. Si desea un menú en el que avanzar desde el último elemento del menú lo lleve de regreso al primero, una forma compacta de hacerlo es usar la operación de módulo (%).

Una vez que el menú seleccionado ha cambiado, la función llama a change_menu_color() para actualizar el color de los elementos del menú.

El código para ui_up es similar, pero en este caso no podemos usar la operación de módulo. En su lugar, usaremos la instrucción if para verificar cuál es el elemento del menú actual:

if selected_menu > 0:
	selected_menu = selected_menu - 1
else:
	selected_menu = 2
change_menu_color()

Cuando se presiona la barra espaciadora o el botón de ataque del joypad, ejecutaremos el código para el elemento de menú resaltado. Para el caso 0 de la declaración de coincidencia (Reanudar juego), ingrese este código:

# Resume game
if not already_paused:
	get_tree().paused = false
player.set_process_input(true)
hide()

Para reanudar el juego, este código establece la propiedad de pausa del árbol del juego en falso (pero solo si el juego no estaba en pausa), reactiva el procesamiento de entrada para el nodo del jugador y oculta el menú.

Reiniciar el juego es sencillo: simplemente debemos recargar la escena principal para que todo vuelva al estado inicial del juego y luego quitar la pausa. Entonces, para el caso 1 de la declaración de coincidencia , ingrese este código:

# Restart game
get_tree().change_scene("res://Scenes/Main.tscn")
get_tree().paused = false

Salir del juego es aún más simple: simplemente llame a la función quit() del árbol del juego. Agregue este código para el caso 2 de la declaración de coincidencia :

# Quit game
get_tree().quit()

Para mayor comodidad, informo a continuación el código final de la función _input ():

func _input(event):
	if not visible:
		if Input.is_action_just_pressed("menu"):
			# Pause game
			already_paused = get_tree().paused
			get_tree().paused = true
			# Reset the popup
			selected_menu = 0
			change_menu_color()
			# Show popup
			player.set_process_input(false)
			popup()
	else:
		if Input.is_action_just_pressed("ui_down"):
			selected_menu = (selected_menu + 1) % 3;
			change_menu_color()
		elif Input.is_action_just_pressed("ui_up"):
			if selected_menu > 0:
				selected_menu = selected_menu - 1
			else:
				selected_menu = 2
			change_menu_color()
		elif Input.is_action_just_pressed("attack"):
			match selected_menu:
				0:
					# Resume game
					if not already_paused:
						get_tree().paused = false
					player.set_process_input(true)
					hide()
				1:
					# Restart game
					get_tree().change_scene("res://Scenes/Main.tscn")
					get_tree().paused = false
				2:
					# Quit game
					get_tree().quit()

Conclusiones

En este tutorial hemos aprendido a hacer un menú de pausa sencillo. Como ejercicio, puede intentar crear un menú similar en la pantalla Game Over.