Horizontal Container
Introducción
Godot maneja bastante bien los layouts para un juego 2D, y todo su sistema de anchors y contenedores funciona muy bien, es algo que me gustó bastante desde el primer día, aunque tengo que decir que tiene ciertas incoherencias que me vuelven loco, por ejemplo algo tan obvio como un padding, en lugar de añadir esto de serie a todos sus controles te crea un contenedor MarginContainer que luego encima solo permite 1 control anidado dentro, asi que para algo tan sencillo (y desde mi punto de vista esencial) te la lia parda anidando contenedores extras.
Esto unido a la locura sus contenedores Flow y lo raro que gestiona el tamaño de los elementos me motivó a crear mi propio contenedor horizontal. La finalidad de mi contenedor es hacer algo muy sencillo, sólo necesitaba meter un score en un juego, poner unos digitos y alinearlos a un lado de la pantalla respetando un padding.
Puede que ya exista algún contenedor para hacer esto? pues ni lo dudo, ni lo confirmo.
Pero yo de momento me voy a montar uno
Qué debe hacer este contenedor
- Crear un control y meter dentro N sprites (en principio todos iguales) y que el control me los organice en línea.
- Que los controles hijos se adapten automáticamente al tamaño del contenedor.
- Configurar alineación: izquierda, centro, derecha y fixed (ajustado al ancho del contenedor).
- Configurar una separación entre los controles, que permita tanto valores positivos como negativos (esta propiedad dentro de la tipografía se llama Kerning asi que matendremos ese nombre para entendernos mejor).
- Configurar un padding en el contenedor para que tenga una separación con los bordes.
- Extra!!! configurar una escala específica a cada control hijo (incluye sample).
El ejemplo más básico
Vamos a ponernos con un ejemplo muy sencillo, un simple contenedor para tener 3 estrellitas. una al lado de la otra, y que se ajusten al tamaño del contenedor, ya está no queremos mas cosas, con este ejemplo podemos ver como ajustamos el contenedor al espacio que tenemos disponibles, y las estrellas ya se encargan de ajustarse al espacio disponible. En un momento dado si queremos añadir alguna estrella, o quitar alguna, el contenedor se encarga de ajustarlas automáticamente.
adentro video
Ajustar ancho por sprites
Este contenedor asume que todos los sprites que tiene dentro van a medir lo mismo de ancho, pero en este ejemplo vamos a tener un sprite que necesita tener un ancho diferente. Pongamos el ejemplo de un Score, con todos los sprites preparados para los digitos, pero con un sprite adicional para el separador de miles que no debe tener el mismo ancho que los digitos ... queda demasiado feo si ocupa lo mismo.
Así que era necesario poder ajustar un factor de escala para cada sprite.
La implementación es más sencilla de lo que parece. En estos ejemplos yo siempre estoy metiendo Sprites dentro del contenedor pero realmente se podria meter cualquier control que herede de Node2D (ya que usa el metodo getsize() para calcular el ancho de cada control). Entonces por reflection yo pregunto al control si tiene una propiedad llamada factor y si la tiene la uso para escalar el ancho del control.
Dicho esto, en este ejemplo, he creado un nodo HContainerSprite2D que hereda de Sprite2D y añade esta propiedad factor (por defecto a 1.0). Además he hecho que cuando esta propiedad se setea, automáticamente llama al método .updatecontrols() del nodo parent, con lo que fuerza el redibujado del contenedor.
@tool
class_name HContainerSprite2D extends Sprite2D
var _factor : float = 1.0
@export var Factor: float:
get:
return _factor
set(value):
_factor = value
# llamamos al contenedor para decirle que recalcule las posiciones
var parent = get_parent()
print (parent)
if parent is HContainer:
parent.updateControls()
Y aquí lo podéis ver en funcionamiento:
Bounding Box VS Gizmos
No entiendo como Godot no tiene un sistema para dibujar Gizmos en pantalla como lo tiene Unity, es algo que me parece fundamental para el desarrollo de juegos, cualquier herramienta que desarrolles, cualquier logica de juego necesitas dibujar lineas de referencia o areas en el mundo que solo ves en el editor.
Pero bueno, como no tenemos gizmos, en este ejemplo los bounding box se construyen a base de añadir un ReferenceRect como hijo de cada Sprite, un ReferenceRect que añado y destruyo cada vez que marcas la opción. No es lo que más me gusta, pero es lo que hay.
Descarga
Aquí os dejo el enlace para descargar el proyecto: