CommunityProgramación y desarrollogithub.com

ziva-sh/godot-control-layout

Construye interfaces de control en Godot 4 que se redimensionan en lugar de recortarse o superponerse: contenedores vs anclajes, presets de anclaje desde código, flags de tamaño, custom_minimum_size, márgenes de MarginContainer, ajuste de texto en Label, mouse_filter, HUDs con CanvasLayer, nombres de anulación de tema en Godot 4 (add_theme_color_override y similares) y la configuración de display/window/stretch para múltiples resoluciones. Úsalo al crear o arreglar menús, HUDs, diálogos y pantallas de inventario, cuando los elementos de UI se cortan, tienen tamaño cero, se superponen o ignoran los contenedores.

¿Qué es godot-control-layout?

Este skill está diseñado para desarrolladores que trabajan con Godot 4 y necesitan crear interfaces de usuario (UI) que se adapten correctamente a diferentes tamaños de ventana. Se enfoca en las tres causas principales de UI rotas: posicionar hijos manualmente dentro de un contenedor, anclar controles sin reiniciar los offsets, y dejar la configuración de estiramiento en sus valores predeterminados. La solución que propone es simple y efectiva: usar contenedores para organizar los elementos, anclar solo la raíz de cada UI y dejar que los tamaños mínimos guíen el resto del diseño. El skill cubre en detalle el uso de todos los contenedores de Godot 4 (VBoxContainer, HBoxContainer, etc.), los flags de tamaño como size_flags_horizontal/vertical, los presets de anclaje (set_anchors_and_offsets_preset), la creación de HUDs persistentes con CanvasLayer, el manejo de texto que no se recorta (autowrap_mode, text_overrun_behavior), y la configuración de resolución y estiramiento en display/window/stretch. También incluye una tabla de equivalencias entre los nombres de anulación de tema de Godot 3 y Godot 4, y una lista de verificación para diagnosticar problemas comunes de UI. Es útil para cualquier proyecto Godot 4 donde se necesiten menús, HUDs, diálogos o pantallas de inventario. Funciona tanto con scripts (GDScript) como con el editor visual de Godot, y se aplica a todos los tipos de controles. El skill asume que el usuario ya tiene conocimientos básicos de Godot 4; no es un tutorial introductorio, sino una guía práctica para resolver problemas específicos de layout.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ziva-sh/godot-skills/tree/HEAD/skills/godot-control-layout

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Layout de controles en Godot 4

La mayoría de las UI rotas en Godot provienen de tres errores: posicionar hijos de un contenedor manualmente, anclar un control sin reiniciar sus offsets, y dejar la configuración de estiramiento en sus valores predeterminados. Diseña con contenedores, ancla solo la raíz de cada UI, y deja que los tamaños mínimos guíen todo lo demás.

Los contenedores son dueños de sus hijos

Un hijo de cualquier Container (VBoxContainer, HBoxContainer, GridContainer, MarginContainer, PanelContainer, CenterContainer, ScrollContainer, FlowContainer) no puede conservar su propio position, size ni anclajes: el contenedor los sobrescribe en el siguiente ordenamiento. Controla la porción de espacio de un hijo con:

  • size_flags_horizontal / size_flags_vertical: Control.SIZE_FILL (por defecto), SIZE_EXPAND_FILL para ocupar espacio sobrante, SIZE_SHRINK_CENTER / SIZE_SHRINK_END para mantenerse pequeño y alineado.
  • size_flags_stretch_ratio: proporción del espacio sobrante entre hermanos que se expanden.
  • custom_minimum_size: el tamaño mínimo que el hijo acepta. Los contenedores nunca reducen un hijo por debajo de su tamaño mínimo combinado, que es como el texto y los botones evitan cortarse.

Elige el contenedor según el layout: filas o columnas (VBoxContainer, HBoxContainer), una cuadrícula (GridContainer con columns), márgenes (MarginContainer, márgenes establecidos por las constantes de tema margin_left, margin_top, margin_right, margin_bottom), un fondo (PanelContainer, style box panel), contenido largo (ScrollContainer con un hijo que tenga SIZE_EXPAND_FILL), elementos que envuelven (HFlowContainer).

Anclajes solo para la raíz

Los anclajes colocan un control en relación con el rectángulo de su padre y son lo que usas para el nodo de UI más externo. Desde código, usa set_anchors_and_offsets_preset(). set_anchors_preset() solo mueve los anclajes y mantiene los offsets antiguos, por lo que un control creado en código se queda con tamaño (0, 0).

Presets: PRESET_FULL_RECT, PRESET_TOP_LEFT, PRESET_TOP_RIGHT, PRESET_BOTTOM_LEFT, PRESET_BOTTOM_RIGHT, PRESET_CENTER, PRESET_TOP_WIDE, PRESET_BOTTOM_WIDE, PRESET_LEFT_WIDE, PRESET_RIGHT_WIDE, PRESET_HCENTER_WIDE, PRESET_VCENTER_WIDE, y los presets de borde central como PRESET_CENTER_TOP.

HUD en un CanvasLayer

Un Control debajo de un Node2D se dibuja en el espacio del mundo y se mueve con la Camera2D. Pon el HUD debajo de un CanvasLayer para que permanezca en pantalla; layer ordena varias capas del canvas (cuanto mayor, más arriba se dibuja).

extends CanvasLayer

var score_label: Label


func _ready() -> void:
	var margin := MarginContainer.new()
	margin.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
	for side in ["margin_left", "margin_top", "margin_right", "margin_bottom"]:
		margin.add_theme_constant_override(side, 16)
	add_child(margin)

	var column := VBoxContainer.new()
	margin.add_child(column)

	var top_bar := HBoxContainer.new()
	column.add_child(top_bar)

	score_label = Label.new()
	score_label.text = "Score: 0"
	score_label.add_theme_font_size_override("font_size", 24)
	score_label.add_theme_color_override("font_color", Color.GOLD)
	top_bar.add_child(score_label)

	var spacer := Control.new()
	spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	spacer.mouse_filter = Control.MOUSE_FILTER_IGNORE
	top_bar.add_child(spacer)

	var pause_button := Button.new()
	pause_button.text = "Pause"
	pause_button.custom_minimum_size = Vector2(96, 40)
	top_bar.add_child(pause_button)


func set_score(value: int) -> void:
	score_label.text = "Score: %d" % value

Construido en el editor, el mismo árbol es: CanvasLayer > MarginContainer (Layout: Full Rect) > VBoxContainer > HBoxContainer > Label, Control (Expand), Button.

Texto que no se recorta

  • Una Label con autowrap_mode establecido necesita un ancho de algún lado. Dentro de un HBoxContainer con flags predeterminados, se colapsa a 1 píxel de ancho y se vuelve muy alta. Dale SIZE_EXPAND_FILL o un custom_minimum_size.x.
  • Para texto de una línea en un espacio fijo, establece text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS (o clip_text = true).
  • Prefiere add_theme_font_size_override("font_size", n) en lugar de escalar un control: scale no cambia el tamaño que los contenedores reservan.
extends VBoxContainer


func add_message(text: String) -> void:
	var label := Label.new()
	label.text = text
	label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
	label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	add_child(label)


func add_title(text: String) -> void:
	var label := Label.new()
	label.text = text
	label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
	label.custom_minimum_size = Vector2(0, 32)
	add_child(label)

Clics que no llegan al juego

mouse_filter decide si un control consume la entrada del ratón. Los valores predeterminados difieren: Control, ColorRect y Panel usan MOUSE_FILTER_STOP, los contenedores usan MOUSE_FILTER_PASS, Label usa MOUSE_FILTER_IGNORE. Un Control o ColorRect a pantalla completa con STOP se traga cada clic, por lo que _unhandled_input() en el juego nunca lo ve. Establece mouse_filter = Control.MOUSE_FILTER_IGNORE en superposiciones, espaciadores y rectángulos decorativos.

Anulaciones de tema (nombres Godot 4)

Godot 3Godot 4
add_color_override("font_color", c)add_theme_color_override("font_color", c)
add_font_override("font", f)add_theme_font_override("font", f)
(el tamaño de fuente vivía en DynamicFont)add_theme_font_size_override("font_size", 24)
add_stylebox_override("normal", sb)add_theme_stylebox_override("normal", sb)
add_constant_override("separation", 8)add_theme_constant_override("separation", 8)
add_icon_override("icon", tex)add_theme_icon_override("icon", tex)
custom_colors/font_color en .tscntheme_override_colors/font_color

Elimina una anulación con el correspondiente remove_theme_*_override(nombre). Para una apariencia consistente, asigna un recurso Theme al control raíz en lugar de anular cada nodo; los hijos lo heredan.

Resolución y estiramiento

Establece esto en Proyecto > Configuración del proyecto > Pantalla > Ventana (se almacenan en project.godot):

  • display/window/size/viewport_width y viewport_height: la resolución base para la que diseñas (por defecto 1152 x 648).
  • display/window/stretch/mode: canvas_items para la mayoría de los juegos (la UI y el 2D se escalan suavemente), viewport para arte pixelado, disabled para herramientas. El modo 2d de Godot 3 es canvas_items en Godot 4. El valor predeterminado es disabled; los proyectos creados en Godot 4.7 o posteriores comienzan con canvas_items.
  • display/window/stretch/aspect: expand permite que la UI anclada use espacio extra en pantallas más anchas o altas; keep agrega barras negras. El valor predeterminado es keep; los proyectos creados en Godot 4.7 o posteriores comienzan con expand.
  • display/window/stretch/scale_mode: integer para arte pixelado nítido.

En tiempo de ejecución, la misma configuración está en la ventana: get_window().content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS y get_window().content_scale_aspect = Window.CONTENT_SCALE_ASPECT_EXPAND.

Lista de verificación cuando la UI está cortada o mal colocada

  1. ¿El control es hijo de un contenedor pero tiene position o size establecidos manualmente? Usa flags de tamaño y custom_minimum_size.
  2. ¿La raíz se ancló solo con set_anchors_preset()? Usa set_anchors_and_offsets_preset().
  3. ¿Una Label con ajuste de texto tiene un ancho?
  4. ¿El HUD está debajo de un CanvasLayer en lugar de un Node2D?
  5. ¿display/window/stretch/mode sigue en disabled mientras el tamaño de la ventana cambia?
  6. ¿Hay un control invisible a pantalla completa con MOUSE_FILTER_STOP encima de todo?

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

ziva-sh/godot-4-api-pitfalls

Fixes Godot 3 APIs and GDScript syntax that AI assistants write into Godot 4 projects, such as KinematicBody2D, move_and_slide(velocity), export, onready, setget, yield, string connect(), instance(), rand_range, the Tween node, File, change_scene, Spatial, rect_* properties, Pool*Array, OS time functions and the old TileMap API. Use when writing, reviewing or porting GDScript for Godot 4.x, when a script fails with "not declared", "not found in base", "was removed in Godot 4" or "is not present

ziva-sh/godot-scene-organization

Structures Godot 4 projects so scenes stay reusable and references do not break - when to make a scene, a script or a Resource, instancing with @export PackedScene, preload and load, @onready and %UniqueName node access, _ready order, groups, autoloads, class_name, and resource UIDs with the .uid files added in Godot 4.4, including how to move or rename files safely. Use when creating new scenes or scripts, deciding how nodes find each other, adding global state or an event bus, moving or renami

ziva-sh/godot-signals

Godot 4 signal patterns and their failure modes - declaring typed signals, emit(), connect() and disconnect() with Callables, bind() and unbind(), lambdas, CONNECT_ONE_SHOT and CONNECT_DEFERRED, await on signals and timers, editor-made connections stored in .tscn files, and the call down, signal up rule. Use when wiring UI buttons, timers, Area2D or body events and custom game events, when replacing Godot 3 connect("signal", self, "method") or yield code, or when debugging "already connected", "

ziva-sh/godot-tilemaplayer

Correct Godot 4.3+ TileMapLayer code - set_cell(coords, source_id, atlas_coords), reading cells and custom data, erasing, coordinate conversion, terrains, tile collision through TileSet physics layers, finding the tile a body hit, and migrating from the deprecated TileMap node and its layer-index API. Use when placing, reading or erasing tiles from GDScript, building a TileSet in code, generating levels procedurally, handling tile collisions, or porting TileMap code from Godot 3 or Godot 4.0 to

Skills relacionados