Godot con 2 nodos ideales para esto: ProgressBar y TextureProgressBar. Con el primero tenemos todo lo que podemos necesitar para una barra básica. El segundo nodo es una evolución el primero, que permite dotarle de una apariencia visual más atractiva, usando texturas en vez de colores plano. En este tutorial nos centraremos en ProgressBar, controlado este, usar el nodo TextureProgressBar es relativamente sencillo.
En Godot2D, ponerle una barra de progreso a tu personaje es muy simple. Te basta con añadir el nodo ProgressBar a la jerarquía de la escena del personaje y luego redimensionar y situar la barra usando sus puntos de agarre visuales.
Lo que quedaría sería la lógica para actualizar los valores de la barra conforme lo hiciesen los del personaje.
Las tres propiedades básicas de un ProgressBar son: MaxValue, MinValue y Value. Las dos primeras se suelen fijar al principio, por ejemplo en el método _Ready(), y definen los valores máximo y mínimo que abarcará la barra. Por su parte, la propiedad Value es la que iremos actualizando a lo largo del juego para que el ProgressBar actualice la longitud de la barra en función del valor de Value en relación con el mínimo y el máximo.
Una aproximación que suelo seguir es crear un script C# para el Sprite3D, con una referencia al ProgressBar:
Las propiedades para los valores mínimo y actual son prácticamente idénticas.
He exportado estas propiedades para poder ponerle valores iniciales desde el inspector. Para que los valores que hayamos configurado en el inspector se apliquen a la barra de progreso, al comenzar el juego, tendremos que tirar del método _Ready():
Una vez arrancado el juego, serán las propiedades las que actualicen el ProgressBar ya que para entonces la referencia a esta no será null.
Lo que queda es ofrecer al exterior un medio para actualizar el valor de la propiedad CurrentValue y, con eso, el de la barra. Puedes hacerlo de muchas maneras, por ejemplo, haciendo que los que scripts que vayan a actualizar la barrar tengan un referencia al script de la barra y, a través de ella, manipulen la propiedad CurrentValue. Sería una aproximación válida, pero incrementaría el acoplamiento al obligar a establecer una referencia directa entre objetos.
Otra opción, que reduzca el acoplamiento, es hacer que los scripts que modifican el nivel de vida emitan señales (la versión de Godot de los eventos) cada vez que se produzca un cambio y que la barra se suscriba a esas señales. En mi ejemplo he seguido ese enfoque y he incluido un handler, en el script de la barra, para responder a ese tipo de señales:
Luego, he suscrito ese handler a la señal emitida por el personaje cada vez que recibe daño:
En el caso de mi ejemplo, la señal del daño la emite el script CharacterLifeManager.cs, el cual define la señal de la siguiente manera:
La emisión de la señal anterior se realiza desde la línea 46 del método ApplyDamage() del script anterior, al cual se llama cada vez que el personaje recibe un golpe de sus contrincantes:
El hecho de usar deltas, en vez de valores absolutos, en el handler OnCurrentValueChanged() permite suscribirlo no sólo a señales de daño (que transmiten deltas negativas) como a señales de curación (cuyas deltas son positivas). En este caso, el script que gestiona las curaciones, cuando el jugador recoge una poción, emite una señal con delta positiva a la que podemos suscribirnos al igual que hicimos con la señal de daño:
La definición de la señal y su lanzamiento es muy similar al caso de la señal de daño, así que no la voy a repasar aquí.
Al basarnos en señales, hemos reducido el acoplamiento entre componentes y hemos conseguido una barra que esa altamente reutilizable ya que la podremos aplicar a cualquier elemento del juego siempre que este emita señales con el valor del incremento (ya sea positivo o negativo) cada vez que se produzca un cambio en el valor monitorizado. De esta manera, podremos reutilizar esta barra de vida, que hemos implementado aquí, con otros componentes para mostrar valores que no tienen por qué ser de vida, como por ejemplo munición, karma o nivel de blindaje.
Aquí acabamos el artículo, espero que te haya gustado. Si las explicaciones y las capturas no te hubiesen sido suficientes, puedes bajar el proyecto que he utilizado de ejemplo desde mi repositorio DungeonRPG en GitHub. He utilizado como base el mini juego que hice al seguir el curso de GameDevTV "Godot 4 C# Action Adventure: Build your own 2.5D RPG", el cual recomiendo muchísimo. El curso no abarca las barras de vida, pero el minijuego que implementa es una base excelente para aprender a crearlas.