Composición por nodos: cómo “se construye” un objeto en Godot
En Godot, un objeto de juego no suele ser una clase monolítica, sino una escena compuesta por nodos. Cada nodo aporta una responsabilidad concreta: transformaciones, render, colisiones, lógica, detección, audio, etc. Esta composición facilita reutilizar piezas, intercambiar componentes y mantener el proyecto escalable.
Nodos clave en 2D y para qué se usan
- Node2D: base para elementos 2D con posición/rotación/escala. Útil como “contenedor” o raíz cuando no necesitas física.
- Sprite2D: muestra una textura estática (un PNG, por ejemplo).
- AnimatedSprite2D: reproduce animaciones basadas en
SpriteFrames(ideal para personajes y efectos 2D frame a frame). - CollisionShape2D: define la forma de colisión (rectángulo, círculo, cápsula, polígono) para un nodo de física o detección.
- CharacterBody2D: cuerpo cinemático para personajes controlados por código (movimiento con
move_and_slide(), gravedad, saltos). - Area2D: zona de detección (triggers): recoger ítems, daño, zonas de interacción, checkpoints.
Recursos: lo que “se enchufa” a los nodos
Los nodos suelen referenciar recursos (assets y configuraciones serializables). Un recurso se puede reutilizar en múltiples escenas y nodos sin duplicar configuración.
Ejemplos de recursos comunes
- Texturas: asignadas a
Sprite2D.texture. - Animaciones: en
AnimatedSprite2Dmediante un recursoSpriteFrames. - Fuentes: recursos de fuente para UI (por ejemplo, en
LabeloRichTextLabel). - Audio:
AudioStream(WAV/OGG) usado porAudioStreamPlayeroAudioStreamPlayer2D.
Idea práctica: si varios enemigos comparten el mismo set de animaciones, conviene que todos apunten al mismo recurso SpriteFrames. Si un enemigo necesita variantes, puedes duplicar el recurso y modificarlo sin afectar a los demás.
Secuencia práctica: de cero a un objeto jugable reutilizable
La siguiente secuencia te sirve como patrón para construir cualquier elemento 2D: elegir nodos adecuados, añadir visuales, agregar colisiones y convertirlo en una escena reutilizable.
Paso 1: elegir el nodo raíz adecuado
Antes de arrastrar nodos, decide qué comportamiento físico o de detección necesitas:
- Escuche el audio con la pantalla apagada.
- Obtenga un certificado al finalizar.
- ¡Más de 5000 cursos para que explores!
Descargar la aplicación
- ¿Se mueve y colisiona como personaje controlado? Usa
CharacterBody2Dcomo raíz. - ¿Es un objeto estático solo visual (decoración)? Usa
Node2DconSprite2D(sin colisiones) o con colisión si lo necesitas. - ¿Es un trigger (zona de daño, pickup, interacción)? Usa
Area2Dcomo raíz.
Regla mental: el nodo raíz suele ser el que define “cómo existe” el objeto en el mundo (física, detección o simple transform).
Paso 2: añadir el componente visual (Sprite2D o AnimatedSprite2D)
Una vez elegido el nodo raíz, añade un nodo visual como hijo:
- Para imagen fija: añade
Sprite2Dy asignaTexture. - Para animación por frames: añade
AnimatedSprite2Dy crea/asigna un recursoSpriteFrames.
Consejo: mantén el nodo visual como hijo del nodo raíz para que herede transformaciones. Si necesitas “ajustar” el sprite sin afectar la colisión (por ejemplo, centrarlo), mueve el Sprite2D localmente, no el nodo raíz.
Ejemplo: configurar AnimatedSprite2D con SpriteFrames
- Crea un
AnimatedSprite2D. - En la propiedad
Sprite Frames, crea un nuevo recursoSpriteFrames. - Agrega animaciones (por ejemplo:
idle,run,jump), y arrastra los frames correspondientes. - Activa
Playingsi quieres previsualizar, y define la animación por defecto.
Paso 3: agregar colisiones (CollisionShape2D) de forma correcta
Las colisiones no se dibujan “solas”: se definen con CollisionShape2D como hijo del nodo que colisiona o detecta. El tipo de nodo padre determina el uso:
- CharacterBody2D + CollisionShape2D: colisión física para movimiento del personaje.
- Area2D + CollisionShape2D: detección de solapamientos (triggers).
Buenas prácticas al crear la forma:
- Elige una forma simple (rectángulo/cápsula) para rendimiento y estabilidad.
- Ajusta la colisión al “volumen jugable”, no al pixel-perfect del sprite. Esto mejora la sensación de control.
- Evita escalar el
CollisionShape2Dcon escalas raras; es preferible editar el tamaño de la forma (por ejemplo, elRectangleShape2D.extents).
Mini-guía: personaje con CharacterBody2D
Estructura típica:
Player (CharacterBody2D)\n├─ AnimatedSprite2D\n└─ CollisionShape2DEjemplo de movimiento básico (conceptual) para ubicar responsabilidades: el CharacterBody2D gestiona velocidad y movimiento; el sprite solo representa el estado.
extends CharacterBody2D\n\n@export var speed := 200.0\n@export var gravity := 900.0\n\nfunc _physics_process(delta):\n if not is_on_floor():\n velocity.y += gravity * delta\n\n var dir := Input.get_axis("ui_left", "ui_right")\n velocity.x = dir * speed\n\n move_and_slide()Nota: este fragmento no “crea” la colisión; asume que ya existe un CollisionShape2D bien configurado como hijo.
Paso 4: usar Area2D para interacción, pickups y daño
Area2D es ideal cuando no quieres empujar físicamente, sino detectar. Estructura típica de un ítem coleccionable:
Coin (Area2D)\n├─ Sprite2D\n└─ CollisionShape2DConecta la señal body_entered para reaccionar cuando un cuerpo (por ejemplo, el jugador) entra en el área:
extends Area2D\n\nfunc _on_body_entered(body):\n if body.name == "Player":\n queue_free()En proyectos reales, en lugar de comparar por nombre, suele ser mejor usar grupos (por ejemplo, body.is_in_group("player")) para mantener el código flexible.
Convertir elementos en escenas reutilizables
Una escena en Godot es un árbol de nodos guardado como archivo (.tscn) que puedes instanciar en otras escenas. Convertir un conjunto de nodos en una escena te permite:
- Reutilizar el mismo objeto (enemigo, moneda, puerta) en múltiples niveles.
- Editar una sola vez y propagar cambios a todas las instancias.
- Encapsular lógica y señales dentro de un “módulo” claro.
Guía paso a paso: de nodos sueltos a escena
- Crea el árbol de nodos (por ejemplo,
Area2D+Sprite2D+CollisionShape2D). - Configura recursos (textura, forma de colisión, animaciones si aplica).
- Adjunta el script al nodo raíz (por ejemplo, al
Area2D). - Guarda como escena (por ejemplo,
Coin.tscn). - Instancia la escena en un nivel: arrástrala desde el FileSystem o instánciala por código.
Instanciar por código (ejemplo)
@export var coin_scene: PackedScene\n\nfunc spawn_coin(pos: Vector2):\n var coin = coin_scene.instantiate()\n coin.global_position = pos\n add_child(coin)PackedScene es un recurso que representa una escena lista para instanciar. Es una forma limpia de spawnear enemigos, proyectiles o pickups.
Criterios: ¿crear una escena nueva o añadir un nodo dentro de la misma escena?
Esta decisión impacta directamente en la mantenibilidad. Usa estos criterios prácticos:
Crea una escena nueva cuando…
- Se reutiliza en más de un lugar (monedas, enemigos, puertas, UI widgets repetidos).
- Tiene lógica propia (scripts, señales, estados) que conviene encapsular.
- Necesitas variantes (por ejemplo,
EnemyBase.tscny escenas heredadas o duplicadas para tipos distintos). - El árbol de nodos crece y empieza a “ensuciar” la escena principal.
- Requiere pruebas aisladas: abrir la escena del objeto y testearlo sin cargar el nivel completo.
Manténlo como nodo dentro de la misma escena cuando…
- Es único y no se repetirá (un fondo específico de un nivel, un trigger exclusivo).
- Es muy simple y no tiene lógica (por ejemplo, un
Sprite2Ddecorativo). - Depende fuertemente del contexto del nivel (por ejemplo, un conjunto de plataformas colocadas a mano que no se reutilizarán).
Regla práctica de escalado
Si dudas, empieza como nodos dentro de la escena. En el momento en que lo copies/pegues por segunda vez o le agregues lógica propia, es una señal clara para convertirlo en escena. Godot facilita refactorizar: puedes seleccionar un nodo con sus hijos y guardarlo como escena para reutilizarlo.
Patrones de composición recomendados (plantillas mentales)
Decoración estática
Decoration (Node2D)\n└─ Sprite2DObjeto interactivo tipo trigger
Trigger (Area2D)\n├─ Sprite2D\n└─ CollisionShape2DPersonaje controlable
Player (CharacterBody2D)\n├─ AnimatedSprite2D\n└─ CollisionShape2DSeparar visual de colisión (cuando necesitas offsets)
Enemy (CharacterBody2D)\n├─ Visual (Node2D)\n│ └─ AnimatedSprite2D\n└─ CollisionShape2DEste patrón permite mover Visual para ajustar animaciones (por ejemplo, un ataque que se estira) sin romper la colisión base.
Recursos en la práctica: cómo organizarlos para reutilización
Texturas
- Úsalas en
Sprite2Do como frames deSpriteFrames. - Si cambias una textura compartida, afectará a todos los nodos que la referencien.
Animaciones (SpriteFrames)
- Un solo recurso
SpriteFramespuede contener múltiples animaciones. - Si varios personajes comparten animaciones, apunta al mismo
SpriteFramespara consistencia.
Fuentes
- Define una fuente como recurso y reutilízala en toda la UI para coherencia visual.
- Si necesitas tamaños distintos, puedes crear variaciones (o configurar overrides por nodo según tu flujo).
Audio
- Un
AudioStream(recurso) se asigna a un reproductor (AudioStreamPlayer2Dpara sonido posicional). - Reutiliza el mismo recurso de audio para múltiples instancias (por ejemplo, el mismo sonido de moneda).
| Necesidad | Nodo típico | Recurso asociado |
|---|---|---|
| Imagen fija | Sprite2D | Texture2D |
| Animación por frames | AnimatedSprite2D | SpriteFrames |
| Colisión física | CharacterBody2D | Shape2D (en CollisionShape2D) |
| Detección/trigger | Area2D | Shape2D (en CollisionShape2D) |
| Sonido 2D | AudioStreamPlayer2D | AudioStream |