Parte: 10 — UI/UX, accesibilidad y localización · Fuente: Documentación de Godot 4 (Size and anchors, Using Containers) ⏱️ Duración estimada: 80 min · Nivel: Intermedio
Dominar el sistema de layout de Godot 4: el nodo base Control, las anclas (anchor presets) y offsets que fijan un elemento respecto a su padre, y los contenedores que posicionan automáticamente a sus hijos. Con estas piezas se construye cualquier pantalla que se adapte sola cuando cambia la resolución, sin colocar nodos "a ojo".
Aprenderás cuándo usar anclas manuales y cuándo dejar que un contenedor decida, cómo funcionan las size flags (SIZE_EXPAND_FILL y compañía) para repartir el espacio, y por qué custom_minimum_size evita que los widgets se aplasten. El laboratorio arma una pantalla real —panel con título, lista desplazable y fila de botones— que se reacomoda al redimensionar la ventana.
Al finalizar, el alumno podrá:
size_flags_horizontal/vertical con SIZE_EXPAND_FILL para repartir espacio.| # | Tema | Por qué importa |
|---|---|---|
| 1 | Nodo Control | Es la base de todo elemento de UI. |
| 2 | Anclas (anchors) | Fijan bordes respecto al padre. |
| 3 | Offsets | Ajustan la distancia exacta a las anclas. |
| 4 | Anchor presets | Atajos para layouts comunes. |
| 5 | Contenedores | Posicionan a los hijos automáticamente. |
| 6 | Size flags | Reparten el espacio sobrante. |
| 7 | custom_minimum_size | Impide que los widgets se aplasten. |
| 8 | Adaptación responsive | La pantalla debe verse bien a cualquier tamaño. |
SIZE_EXPAND_FILL hace que ocupe el espacio disponible.Trabaja en Godot 4.x con un proyecto vacío o el del curso. Configura antes el estiramiento en Project → Project Settings → Display → Window → Stretch: pon Mode en canvas_items y Aspect en keep para probar bien la adaptación.
Ten a mano dos referencias de Godot: Size and anchors (https://docs.godotengine.org/en/stable/tutorials/ui/size_and_anchors.html) y Using Containers (https://docs.godotengine.org/en/stable/tutorials/ui/gui_containers.html). Casi todo el trabajo es en el editor; el script solo rellena la lista.
Montaremos una pantalla con un panel central que contiene título, una lista con scroll y una fila de botones. Todo debe reacomodarse al redimensionar.
Crea una escena con raíz Control llamada Pantalla. Selecciónala y aplica el anchor preset Full Rect (botón de anclas → Full Rect) para que llene la ventana.
Añade un PanelContainer (Panel). Con él seleccionado, aplica el preset Center y en el Inspector fija custom_minimum_size a (480, 360). Así el panel queda centrado con un tamaño mínimo garantizado.
Dentro del Panel añade un MarginContainer y pon sus theme_override_constants/margin_* en 16. Dentro, un VBoxContainer (Contenido) con theme_override_constants/separation en 12.
En Contenido añade en orden: un Label (Titulo, texto "Inventario"), un ScrollContainer (Scroll) y un HBoxContainer (Botones).
Selecciona el Scroll y pon size_flags_vertical en Fill, Expand (equivale a SIZE_EXPAND_FILL): así la lista se queda con todo el espacio vertical sobrante entre el título y los botones. Dentro del Scroll añade un VBoxContainer (Items).
En Botones añade dos Button ("Usar" y "Cerrar"). A cada uno ponle size_flags_horizontal en Fill, Expand para que se repartan el ancho por igual.
Selecciona Pantalla, Attach Script, guarda como pantalla.gd para llenar la lista por código:
extends Control
@onready var items: VBoxContainer = $Panel/MarginContainer/Contenido/Scroll/Items
@onready var boton_cerrar: Button = $Panel/MarginContainer/Contenido/Botones/Cerrar
func _ready() -> void:
# Generamos filas de ejemplo para ver el scroll en acción.
for i in range(20):
var fila := Label.new()
fila.text = "Objeto %02d" % (i + 1)
items.add_child(fila)
boton_cerrar.pressed.connect(_on_cerrar)
func _on_cerrar() -> void:
print("Cerrar inventario")
Ejecuta con F6. Debes ver el panel centrado con 20 objetos desplazables y dos botones iguales abajo. Ahora redimensiona la ventana: el panel permanece centrado, la lista crece o encoge y los botones mantienen su fila. Esa es la adaptación automática que dan anclas + contenedores.
Comprueba la regla clave: intenta arrastrar en el editor uno de los Label dentro de Items. Verás que vuelve a su sitio, porque su padre es un contenedor. Para reordenar, cambia el orden de los hijos en el árbol; para cambiar tamaños, ajusta size flags o custom_minimum_size, nunca la posición a mano.
Con este patrón —raíz Full Rect, panel centrado con mínimo, contenedores anidados y size flags— tienes la base de cualquier pantalla adaptable del curso.
Panel a Top Wide y observa cómo pasa a ocupar todo el ancho superior.HBoxContainer de botones por un GridContainer de 2 columnas con cuatro botones.size_flags_vertical del Scroll en solo Fill (sin Expand) y explica qué cambia.custom_minimum_size del panel y verifica que nunca baja de ese mínimo al encoger la ventana.Titulo en un CenterContainer para centrarlo horizontalmente sin tocar sus anclas.Construye una pantalla de dos columnas: a la izquierda una lista con scroll (que ocupe el 40% del ancho) y a la derecha un panel de detalle. Usa un HBoxContainer con size flags para el reparto y custom_minimum_size para que ninguna columna colapse. Debe seguir viéndose bien a 1280×720 y a 640×360.
Criterio de aceptación: al redimensionar entre ambas resoluciones, las dos columnas mantienen su proporción, la lista conserva su scroll y ningún widget se solapa ni se aplasta por debajo de su mínimo.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
| Muevo un hijo y vuelve a su sitio | Está dentro de un contenedor; la posición la decide el padre, no tú. |
| Todo se apila en la esquina superior | Faltan anclas/preset o falta un contenedor que ordene. |
| Un botón ocupa todo el ancho él solo | Solo ese hijo tiene SIZE_EXPAND_FILL; ponlo en los demás también. |
| El scroll no aparece | El contenido no supera la altura; falta SIZE_EXPAND_FILL en el ScrollContainer. |
| El panel se aplasta al encoger | No definiste custom_minimum_size. |
❓ ¿Anclas o contenedores? Contenedores para estructuras que se repiten o adaptan; anclas manuales para elementos sueltos como un logo o un HUD fijo.
❓ ¿Por qué no puedo mover un nodo dentro de un contenedor? Porque el contenedor recalcula la posición de sus hijos cada frame. Cambia el orden o las size flags en su lugar.
❓ ¿Qué hace exactamente SIZE_EXPAND_FILL? Pide al contenedor que ese hijo reciba parte del espacio sobrante (Expand) y lo rellene (Fill).
❓ ¿Full Rect y Center se pueden combinar con contenedores? Sí: el nodo raíz suele ir Full Rect y dentro colocas contenedores que gestionan el resto.
Clase 188 - Fundamentos de UI/UX en juegos