Home »

Tutorial de Patapang V: Animando al protagonista

Poco a poco hemos llegado bastante lejos, tanto en el juego como en nuestro conocimiento de Godot. Vamos a dar los siguientes pasos, que hoy toca hacer cosas muy chulas.

Para esta parte del tutorial necesitaremos muchos nuevos recursos gráficos. Primero, algunas imágenes para las burbujas:

resources/images/bubble_blue.png
resources/images/bubble_green.png
resources/images/bubble_red.png
resources/images/bubble_yellow.png

Y luego, un montón de imágenes para nuestro protagonista. Os dejamos todas en un zip para que no sea una locura descargarlas.
Deben ir todas a resources/images/sprites/adventure_guy/ (por ejemplo, resources/images/sprites/adventure_guy/Idle__000.png)

adventure_guy.zip

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

Antes de nada, vamos a unir las dos pantallas que hemos hecho hasta ahora. Nuestro juego, como es lógico, comienza en el menú principal. Vamos a hacer que, al pulsar el PlayButton aparezca la pantalla de juego.

Godot tiene un concepto llamado “árbol de escenas” (“SceneTree”), en el que no vamos a entrar ahora. Basta con que sepas que define qué escena está cargada, y por lo tanto que escena va a ver el jugador. Para cambiar de una escena a otra basta con llamar a get_tree().change_scene().

Como ya teníamos asociado el evento al hacer click en PlayButton, tenemos que modificarlo. Abre el código MainMenu.gd y localiza la función _on_PlayButton_gui_input. Modifícala para que, al pulsar el botón, abra la escena Play.tscn.

1
2
3
func _on_PlayButton_gui_input(event):
if event is InputEventMouseButton and event.pressed and event.button_index == 1:
get_tree().change_scene("res://Play.tscn")

Si ejecutas el juego con F5, verás el menú principal. Pero ahora, si pulsas en el botón de play, ¡cambiarás a la pantalla de juego!.

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

El protagonista se tiene que mover

Ahora que ya podemos acceder a la escena de juego cómodamente, vamos a seguir con ella.
En la entrega anterior hicimos que nuestro protagonista mirase a un lado o a otro. El siguiente paso es conseguir que se mueva.

Para mover un elemento por la pantalla tenemos dos opciones:

Moviendo “a mano”

Una sería hacer los cálculos matemáticos para calcular el punto donde queremos que esté teniendo en cuenta el tiempo. En nuestro caso, que el personaje solo se va a mover a derecha e izquierda, no sería un cálculo complejo. Por ejemplo, para que se moviese 500px por segundo podríamos hacer algo tipo:

1
position.x += SPEED * delta

Sin embargo para movimientos más complejos esto se vuelve muy farragoso. Y además hay un punto importantísimo: en breve querremos detectar colisiones entre objetos. ¿Cómo sabemos si un objeto choca con otro? ¿Y qué pasa entonces? ¿Lo empuja? ¿Se queda parado?. Para nuestro juego es importantísimo saber si una burbuja choca con el protagonista, ya que le haría perder. Si hacemos los cálculos de movimiento nosotros, también deberíamos hacer los cálculos de colisiones nosotros. Y es algo que se vuelve muy complejo, que no aporta nada a nuestro juego (ya que es igual para todos los juegos), y que además… ¡Ya está hecho! ¡Godot nos da esa funcionalidad directamente!

Moviendo con vectores

Godot nos ofrece un motor de física muy avanzado, que permite mover objetos y que interactúen entre ellos de forma muy sencilla. Una de las formas que nos da Godot para mover objetos (y la que vamos a usar nosotros) es simplemente aplicarles una fuerza, y dejar que el motor de física calcule el resultado.
¿Y cómo definimos una fuerza? Pues con un vector.

Pero no te preocupes: no vamos a meternos a explicar física, ni cómo se representan fuerzas con vectores. Basta con que entiendas que si quieres mover un objeto a la izquierda o derecha debes poner valores en la propiedad “x” del vector, si quieres moverlo arriba o abajo en la propiedad “y”, y si quieres moverlo en diagonal, ambas deben tener un valor.

Una vez has definido un vector, se aplica al objeto que quieras mover, y Godot hace todos los cálculos necesarios (teniendo en cuenta incluso el delta, el tiempo que ha pasado desde la última vez que se calculó) para decidir la nueva posición del objeto.

¿Y cómo se traduce todo esto a código? Pues de forma mucho más sencilla de lo que parece. Lo primero, en el fichero Player.gd tienes que crear una variable motion que representa el vector de movimiento del que hemos hablado. Además, vamos a definir una constante SPEED con la velocidad a la que quieres que se mueva el protagonista (nosotros hemos puesto 500, pero puedes jugar con ese valor para ver qué pasa):

1
2
const SPEED = 500
var motion = Vector2()

Y ahora modificamos _physics_process para que aplique ese vector cada vez que se llame a esa función (que son muchas veces por segundo), sin olvidarnos de que lo que queremos es movernos a izquierda o derecha según los cursores:

1
2
3
4
5
6
7
8
9
10
11
func _physics_process(delta):
if Input.is_action_pressed("ui_right"):
motion.x = SPEED
$TextureRect.flip_h = false
elif Input.is_action_pressed("ui_left"):
motion.x = -SPEED
$TextureRect.flip_h = true
else:
motion.x = 0

motion = move_and_slide(motion)

Si ejecutas ahora el juego, por fin podrás mover el protagonista usando los cursores.

Hay muchíiiisimo más que decir sobre el motor de física y el movimiento de objetos, pero no nos hace falta para este tutorial. Si te interesa, puedes mirar la documentación oficial sobre physics, especialmente using_kinematic_body_2d

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

¡El protagonista se tiene que mover tiene que correr!

Aunque ya tengamos la funcionalidad, visualmente este movimiento deja mucho que desear. Para que esto se vea bien, tiene que parecer que el protagonista está corriendo, y ahora es una imagen que se desliza…

Es el momento de hablar de los sprites animados.

Un sprite animado es, como su nombre indica, un sprite que está animado. ¿Y eso qué significa? Pues es un tipo de nodo de Godot que es capaz de definir una o varias animaciones. Una animación es una secuencia de imágenes, que se pintan sucesivamente para hacer un efecto. En nuestro caso, el efecto de andar.

Abre la escena Player, y en el árbol de nodos añade a Player un nuevo nodo hijo de tipo AnimatedSprite. Luego en el inspector despliega los valores posibles de la propiedad Frames y elige New Spriteframes.

Ahora pincha en el valor de la propiedad (donde en vez de “[empty]” ahora pone “SpriteFrames”), y en la parte inferior de la pantalla se abrirá el editor de animaciones.

TIP: Este comportamiendo del editor es un poco extraño al principio. Hay propiedades en el inspector cuyos valores son elementos complejos, que al pinchar abren otras propiedades o en este caso otras secciones del editor. No es ideal, pero te acabas acostumbrando...

El editor de animaciones

Este editor es bastante completo, y permite crear animaciones rápida y fácilmente, pero la primera vez es un poco complejo de entender. A la izquierda hay un listado de todas las animaciones definidas (y justo encima de la lista hay botones para crear nuevas animaciones, o borrar las existentes). Por defecto solo existe una, que se llama “default”. Lo primero que vamos a hacer es cambiarle el nombre por algo más descriptivo. Haz doble click sobre “default” y ponle como nombre “adventure_guy_running”.

Ahora tenemos que añadir las imágenes que van a componer esta animación. En el sistema de archivos, navega hasta la ruta resources/images/sprites/adventure_guy. Desde ahí arrastra todas las imágenes que empiezan por “Run” al hueco grande del centro.

¡Oh! La imagen no está donde debería. Eso es porque el AnimatedSprite tiene marcada la propiedad “Centered”. Quitasela en el Inspector. Y ya que estás, activa la propiedad “Playing” para que la animación comience automáticamente. ¡Esto empieza a tener muy buena pinta!. Lo que pasa es que corre muy despacio, ¿no?. Vamos a acelerar la animación. Debajo de la lista de animaciones puedes definir la velocidad. Juega con los valores donde pone “Speed (FPS)” hasta encontrar una que te guste (por ejemplo, con 15 queda bastante bien).

Como puedes ver, nuestro viejo nodo TextureRect con la imágen estática ya no nos vale de nada, así que vamos a quitarlo. Seleccionalo en el árbol de nodos y borralo. Por último, en el código de Player.gd se hacía referencia a “TextureRect” para hacerlo mirar a un lado o a otro. Cambia esas referencias por unas a “AnimatedSprite”.

1
2
3
4
5
6
7
8
9
10
11
func _physics_process(delta):
if Input.is_action_pressed("ui_right"):
motion.x = SPEED
$AnimatedSprite.flip_h = false
elif Input.is_action_pressed("ui_left"):
motion.x = -SPEED
$AnimatedSprite.flip_h = true
else:
motion.x = 0

motion = move_and_slide(motion)

¡Y por fin lo tenemos! Ejecuta el juego, y verás que con esta animación el protagonista corre fenomenal por toda la pantalla.

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

Más animaciones

Aunque es genial que el protagonista ya pueda correr, vamos a hacer que pueda hacer más cosas: Quedarse de pie, saltar, e incluso morir (oooh).

Como ya sabes crear animaciones, vamos a ir más rápido. En el editor de animaciones dale al botón “+” para crear una nueva. Por defecto le pondrá el nombre “New Anim”. Haz doble click sobre ese nombre para cambiarlo a “adventure_guy_idle”. Arrastra al espacio central todas las imágenes que empiezan por “Idle” de la ruta resources/images/sprites/adventure_guy. Y ponle una velocidad de 8 FPS.

Vuelve a hacer lo mismo y crea una nueva animación “adventure_guy_dead” con las imágenes que empiezan por “Dead”. Deja la velocidad de 5 FPS que viene por defecto, pero justo debajo desactiva el “Loop”, para que esta animación se ejecute solo una vez, y no vuelva a comenzar cuando finalice.

Y repite el proceso una última vez, con una animación llamada “adventure_guy_jump”, las imágenes que empiezan por “Jump”, una velocidad de 20 FPS, y sin “Loop”.

Las animaciones “adventure_guy_dead” y “adventure_guy_jump” aún no vamos a usarlas. Pero vamos a modificar nuestro código para que, mientras el jugador no toque los cursores, y el protagonista esté quieto, se reproduzca la animación “adventure_guy_idle”. Y cuando el personaje se esté moviendo, se reproduzca “adventure_guy_run”.

Lo primero que tenemos que hacer es hacer que inicialmente el protagonista empiece con la animación “adventure_guy_idle”. Para ello tienes que ir a las propiedades de AnimatedSprite y elegir “adventure_guy_idle” como valor de la propiedad Animation.

A continuación vamos a modificar el código de Player.gd, y modificar la animación que queremos mostrar. Es tan sencillo como hacer $AnimatedSprite.animation = "adventure_guy_running".

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func _physics_process(delta):
if Input.is_action_pressed("ui_right"):
motion.x = SPEED
$AnimatedSprite.flip_h = false
$AnimatedSprite.animation = "adventure_guy_running"
elif Input.is_action_pressed("ui_left"):
motion.x = -SPEED
$AnimatedSprite.flip_h = true
$AnimatedSprite.animation = "adventure_guy_running"
else:
$AnimatedSprite.animation = "adventure_guy_idle"
motion.x = 0

motion = move_and_slide(motion)

¿A qué esperas? ¡Ejecuta el juego para que veas lo bien que queda!

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

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


Tutorial: