Home »

Tutorial de Patapang (III): construyendo nuestro menú principal del videojuego con Godot

Vamos a seguir construyendo nuestro menú principal, que nos servirá de excusa para aprender algunos conceptos adicionales de Godot.
Antes de empezar, necesitaremos algunos recursos gráficos extra, bien ordenados en sus directorios de recursos:

resources/fonts/Chocolate Covered Raindrops.ttf
resources/images/adventure_guy.png
resources/images/gui/fx.png
resources/images/gui/fx_off.png
resources/images/gui/music.png
resources/images/gui/music_off.png
resources/images/gui/play.png
resources/images/logo.png
resources/sound/glitter-blast.ogg
resources/sound/pop.wav

Puedes poner directamente el proyecto en este punto desde esta rama de git: https://gitlab.com/pablo_alba/patapangtutorial/-/tree/step04

Añadir más imágenes

Anteriormente vimos que se podían añadir imágenes a nuestra escena creando un nodo de tipo “ImageRect”, y luego añadiendo la imagen como textura. Vamos a repetir este proceso para añadir la imagen “adventure_guy.png”. Una vez añadida, en el editor visual puedes pinchar y arrastrar la imagen para colocarla donde quieras. ¡Hazlo ahora! Tu objetivo es conseguir este resultado:

TIP: Asegúrate de que añades el segundo nodo “TextureRect2” como hijo de “MainMenu”, y no de “TextureRect1”. Si te equivocas, puedes reordenar y reorganizar los nodos arrastrandolos con el ratón

¡Esto va cobrando forma! Recuerda que si das F5 (o al botón de play) se ejecuta el juego, y podrás ir viendo el resultado.

Ahora haz lo mismo con el “logo.png”, y colocalo en el centro. Y ya puestos, aprovecha para renombrar los nodos, y que quede más claro en el árbol qué es cada cosa.

Mmm… se ve un poco pequeño, ¿no?. Podríamos editar la imagen en Gimp para hacerla más grande. Pero en su lugar vamos a aprovechar para mirar un poco más las propiedades de los nodos.

Con el nodo “Logo” seleccionado, en el Inspector vemos sus propiedades. Despliega la sección “Rect”. Ahí podrás ver las propiedades del rectángulo que contiene la imagen. Por ejemplo, si cambias las propiedades de “Position/x” a 1200 y Position/y a 600, verás como el logo se desplaza. Muchas veces es más útil situar los elementos en puntos exactos en lugar de con el ratón.

Pero lo que queríamos era hacerlo más grande. Para ello podemos poner las propiedades “Scale/x” y “Scale/y” a 2, y veremos la imagen el doble de grande. Si dejamos ese “scale”, y ponemos las posiciones “x” e “y” a 600 y 0, el resultado debe ser este:

Añadir “botones”

Ahora vamos a entrar en un tema muy debatible. Godot tiene unos nodos especiales para botones, que admiten textos, diferentes imágenes para cuando están pulsados y no, y un montón de cosas más. Sin embargo, Godot les mete cierto estilos y sombreados por defecto, y además una vez pulsados se quedan como seleccionados, produciendo un efecto que no nos gusta.

Así que en lugar de usar nodos de tipo botón, vamos a usar simples imágenes, y más adelante haremos que actuen como botones.

A estas alturas seguro que no hace falta que te demos instrucciones, pero por reforzar: Añade tres nuevos nodos de tipo “TextureRect”, y ponles como texturas “play.png”, “music.png” y “fx.png”. A continuación juega con los tamaños para conseguir que tu escena quede así

Puedes poner directamente el proyecto en este punto desde esta rama de git: https://gitlab.com/pablo_alba/patapangtutorial/-/tree/step05

Música

Una parte importantísima en un juego es la música y los efectos de sonido. Acentúan mucho la inmersión del jugador en el juego, y suponen una gran diferencia en la experiencia. Por fortuna, Godot nos lo pone muy sencillo para añadir música a una escena. Basta con que añadas como hijo de “MainMenu” un nodo de tipo “AudioStreamPlayer”. Para elegir el clip de sonido para este nodo haremos algo similar a lo que hacíamos con las imágenes: arrastrar el fichero “glitter-blast.ogg” desde el sistema de ficheros a la propiedad “Stream” de este nodo en el inspector. Y ya que estamos en el inspector, marca el check de “Autoplay” para que se reproduzca automáticamente al cargar la escena. Guarda con Ctrl+S, ejecuta el juego con F5 y… ¡Esto parece cada vez más un juego!

Puedes poner directamente el proyecto en este punto desde esta rama de git: https://gitlab.com/pablo_alba/patapangtutorial/-/tree/step06

Hola mundo

Hasta este punto hemos hecho todo de forma gráfica, con el editor. ¿Es que en Godot no se programa? Pues sí, y ha llegado el momento de empezar.

Godot permite programar en diversos lenguajes. Pero por defecto, utiliza GDScript, un lenguaje propio de alto nivel muy similar a python.

Para escribir código en una escena hay que asociarle un script. Para ello, pulsamos en el nodo raíz “MainMenu” y hacemos click en el icono . Dejamos los valores por defecto, y pulsamos “Create”.

Esto creará un nuevo script llamado “MainMenu.gd” asociado a nuestra escena. Además, nos cambiará la parte central del editor y en lugar de ver la previsualización, veremos el código fuente del script.

TIP: Siempre puedes cambiar entre ver la previsualización y el código fuente con los botones de la parte superior. Pulsa “2D” para la previsualización, y “Script” para el código fuente.

El script se crea a partir de una plantilla, así que aparece ya con un poco de código.

La función ‘ready’ se llama automáticamente cuando se carga la escena. Por homenajear a los clásicos, escribe en esa función el siguiente código:

1
2
func _ready():
print ("Hello World!")

Guarda, ejecuta con F5, y verás abajo del editor, en la ventana de “Output”, que efectivamente la ejecución de la escena ha escrito la salida “Hello World!”

Puedes poner directamente el proyecto en este punto desde esta rama de git: https://gitlab.com/pablo_alba/patapangtutorial/-/tree/step07

Botones y señales

Las señales son la versión de Godot del patrón observador. Permiten que un nodo emita un mensaje, al que otros nodos (o tu código) pueden escuchar y responder. Por ejemplo, en lugar de estar comprobando constantemente si un botón está pulsado, el botón puede emitir una señal cuando sea pulsado.

Y eso es justo lo que vamos a hacer. Vamos a escuchar la señal que emite un botón, y parar o poner en marcha la música a partir de ella.

Como verás, Godot nos lo pone fácil para enganchar nuestro código a una señal.

Primero, renombra los últimos nodos TextureRect que añadiste para que tengan un nombre representativo. Llamalos “PlayButton”, “MusicButton”, y “FxButton”.

Ahora pulsa en el árbol de nodos sobre “MusicButton”. Como siempre, en el Inspector verás sus propiedades. Pero lo que nos interesa ahora es la pestaña que está al lado del Inspector, llamada “Node”. Ahí puedes ver todas las señales de este nodo.

Si haces doble click sobre una de ellas, Godot asociará esa señal con una función en tu script. En este caso nos interesa engancharnos a la señal que emite cuando el usuario pulsa sobre él. Así que haz doble click sobre “gui_input(event: InputEvent)”, y verás un cuadro de diálogo. Deja los parámetros tal cual y pulsa “Connect”.

Verás que Godot te ha creado una nueva función en tu script, a la que se llamará automáticamente cuando este nodo reciba algún tipo de interacción por parte del usuario. Como nosotros queremos reaccionar a algo específico (cuando el usuario pulsa la imagen), podemos escribir en la función el siguiente código:

1
2
3
func _on_PlayButton_gui_input(event):
if event is InputEventMouseButton and event.pressed and event.button_index == 1:
print("User click")

Si ejecutamos con F5, veremos como en la sección de Output nos aparece “User click” cada vez que pulsamos sobre el botón de la música.

Nuestro siguiente paso es conseguir encender o parar la música en lugar de escribir en el output.

En GDScript tenemos una nomenclatura para hacer referencia a un nodo del árbol de la escena. Hay que poner el símbolo $ y luego la ruta del nodo. En nuestro caso, para hacer referencia al nodo del reproductor de música sería “$AudioStreamPlayer”.

La documentación de Godot es muy completa, y nos da información de todos los métodos y propiedades de los nodos. En este caso, vemos en la documentación del AudioStreamPlayer que tiene la propiedad “playing” y los métodos “play” y “stop”. Así que podemos escribir este código:

1
2
3
4
5
6
func _on_MusicButton_gui_input(event):
if event is InputEventMouseButton and event.pressed and event.button_index == 1:
if $AudioStreamPlayer.playing:
$AudioStreamPlayer.stop()
else:
$AudioStreamPlayer.play()

Si ejecutamos, veremos que ahora la música se para y vuelve a arrancar según pulsamos el botón.

Puedes poner directamente el proyecto en este punto desde esta rama de git: https://gitlab.com/pablo_alba/patapangtutorial/-/tree/step08

Más señales y un sonido

Vamos a hacer algo muy parecido con el botón de sonidos, el que hemos llamado “FxButton”. Queremos que al pulsarlo suene un “pop”.
Lo primero, vamos a añadir un nuevo nodo de tipo “AudioStreamPlayer” a “MainMenu”. Por aprender más cosas sobre Godot, esta vez en lugar de añadirlo como siempre, ve al árbol de nodos, pulsa sobre el “AudioStreamPlayer” que ya tenemos, y pulsa ctrl+d (o botón derecho / Duplicate) para duplicar el nodo. Esto crea una copia del mismo, con los mismos valores. Es una funcionalidad muy útil, porque al copiar todos los valores, te puede ahorrar mucho trabajo.

Al duplicar el nodo, vemos que le ha dejado un nombre bastante poco descriptivo. Así que renombra el nodo “AudioStreamPlayer1” a “AudioStreamPop”.

A continuación, arrastra el fichero “pop.wav” desde el sistema de ficheros a la propiedad “Stream” del nodo “AudioStreamPop”. Y, en el Inspector, desmarca la propiedad “Autoplay” para que no suene al arrancar la escena.

Y ahora, hacemos lo mismo que antes. Con el nodo “FxButton” seleccionado en el árbol de nodos, vamos a la pestaña “Node” al lado del Inspector, hacemos doble click sobre “gui_input”, pulsamos “Connect”, y en la ventana de código escribimos lo siguiente:

1
2
3
func _on_FxButton_gui_input(event):
if event is InputEventMouseButton and event.pressed and event.button_index == 1:
$AudioStreamPop.play()

Ejecuta con F5 y dale sin parar al botón de Fx. Qué satisfactorio, ¿verdad?

Puedes poner directamente el proyecto en este punto desde esta rama de git: https://gitlab.com/pablo_alba/patapangtutorial/-/tree/step09

Mostrar y ocultar

Hasta ahora hemos visto que todos los nodos que añades a una escena, los ves al ejecutar la escena. Pero eso no tiene por que ser siempre así. Hay veces que queremos tener cosas ocultas, que se muestren según las acciones del usuario.

Por ejemplo, en realidad en esta pantalla lo que queremos configurar es si se deben o no reproducir los efectos de sonido y/o la música en nuestro juego. Así que vamos a mostrar los botones en color o en gris según estén la música y los efectos activos o no.

Como siempre, hay muchas formas de abordar esto, pero vamos a hacerlo de la manera más simple. En el árbol de nodos pincha en “MusicButton” y duplicalo con ctrl+d. ¡Estupendo! Como nos ha duplicado las propiedades, está situado justo donde queremos: en la misma posición que “MusicButton”. Renombra el nuevo nodo como “MusicButtonOff”, y ponle como textura la imagen “music_off.png”.

Ahora vamos a configurar también una señal para este nodo. Con “MusicButtonOff” seleccionado en el árbol de nodos, ve a la pestaña “Node” al lado del Inspector y… ¡Oh!. ¡Ya tiene la señal “gui_input” conectada. Al duplicar el nodo, también se duplican sus señales. Recuerda esto, porque puede ser la fuente de bugs en el futuro.

Por ahora, la solución es fácil. Pincha en la conexión preexistente, marcada en verde (con el texto “.. :: _on_MusicButton_gui_input”), y abajo de la pestaña pulsa en “Disconnect”. Listo, ya está borrada. Ahora sí, haz doble click sobre “gui_input”, y pulsa connect.

Este botón se va a mostrar cuando la música está desactivada. Lo que queremos conseguir al pulsarlo son tres cosas:
1. Que el botón “MusicButtonOff” se oculte
2. Que el botón “MusicButton” se muestre
3. Que la canción empiece a sonar

Para ello, escribe este código:

1
2
3
4
5
func _on_MusicButtonOff_gui_input(event):
if event is InputEventMouseButton and event.pressed and event.button_index == 1:
$AudioStreamPlayer.play()
$MusicButtonOff.hide()
$MusicButton.show()y()

Además, vamos a cambiar lo que hace el botón “MusicButton” de forma simétrica. Modifica el código que ya teníamos para que quede así:

1
2
3
4
5
func _on_MusicButton_gui_input(event):
if event is InputEventMouseButton and event.pressed and event.button_index == 1:
$AudioStreamPlayer.stop()
$MusicButtonOff.show()
$MusicButton.hide()

Una última cosa. Queremos que al arrancar el botón “MusicButtonOff” esté oculto. En el árbol de nodos, justo al lado de su nombre, hay un icono de un ojo. Si lo pulsamos, podemos hacer que un nodo empiece visible u oculto. Pinchalo para ocultarlo.

¡Ya lo tenemos! Arranca con F5, y verás que ahora al pulsar el botón de la música, además de pararse la canción, parece que “cambia” a gris. Y si lo pulsas cuando está gris, comienza la canción, y vuelve a colorearse.

Puedes poner directamente el proyecto en este punto desde esta rama de git: https://gitlab.com/pablo_alba/patapangtutorial/-/tree/step10

“Deberes” para ti

Pues ya va siendo hora de que pruebes tus habilidades sin que te guiemos paso a paso. Tu misión es conseguir el mismo efecto de botón de color/gris para el botón de sonidos “FxButton”.

Lo que debes conseguir es:

  • Que el juego empiece con un botón de sonidos coloreado. Al pulsar ese botón:
    1. Debe ocultarse el botón de sonidos coloreado
    2. Debe mostrarse el botón de sonidos gris
  • Y al pulsar el botón de sonidos gris:
    1. Debe mostrarse el botón de sonidos coloreado
    2. Debe ocultarse el botón de sonidos gris
    3. Debe sonar “pop”

¡Suerte!

Puedes poner directamente el proyecto en este punto desde esta rama de git: https://gitlab.com/pablo_alba/patapangtutorial/-/tree/step11

¡Continuará! Cada semana, un nuevo post tutorial.


Tutorial: