~/devBitácora← Volver al inicio
Devlog #6Sep 2026

"Interfaces" en Godot 4: Escalabilidad usando Resources y Composición

Aplica Clean Code al gestionar decenas de ítems en tu juego aplicando contratos, herencia de recursos y patrones de diseño tradicionales.

Imagen destacada para "Interfaces" en Godot 4: Escalabilidad usando Resources y Composición

Cuando empecé a añadir ítems coleccionables o (pickups) al prototipo del Action-Adventure en 2D que estoy construyendo en mi formación, me topé con el primer problema (clásico) de escalabilidad.

Al ir incorporando items como llaves, monedas, pociones de vida o mejoras de ataque, la tendencia inicial (lo que se enseña en muchos tutoriales rápidos) es crear una escena distinta para cada uno, o peor aún, tener un único script enorme (code smell) en el jugador con un bloque match gigante a modo árbol de casos (independientemente si es con literal pattern, dictionary pattern…).

A nivel de arquitectura de software, supone un problema de acoplamiento y de escalabilidad. Una buena solución: aplicar el concepto de Interfaces (o contratos) utilizando como tal los Resources que ofrece Godot.

1. Definiendo el contrato (La clase base)

En lugar de programar la lógica en los nodos físicos, primero declaro una clase Item que extiende de Resource. Esta clase va a actuar a modo de interfaz, definiendo las propiedades básicas que todo ítem debe tener y, lo más importante, un método vacío llamado use_with() que servirá como contrato.

class_name Item extends Resource

@export var name := ""
@export var texture: Texture2D = null
@export var sfx_pickup: AudioStream = null

# Contrato a definir en cada tipo de Item específico
func use_with(player: Player) -> void:
	pass

2. Implementando el ítem (polimorfismo)

Ahora, si quiero crear un objeto que aumente permanentemente el daño de ataque del personaje al recogerlo, no necesito tocar el código del jugador. Simplemente creo un nuevo script que herede del ya declarado Item base e implemento su propia versión de la función use_with().

class_name DamageUpgradeItem extends Item

@export_range(1, 10, 1) var damage_boost := 2

func use_with(player: Player) -> void:
	# El ítem contiene su propia lógica y modifica al jugador
	player.base_damage += damage_boost

Desde el editor de Godot, ahora puedo crear tantos ficheros .tres como necesite basados en DamageUpgradeItem, configurando distintos iconos o incrementos de daño en el inspector, sin duplicar código (DRY).

3. Un único nodo orquestador

Haciendo uso de la composición, ya no necesito construir una escena completa para cada objeto del juego. Es suficiente con montar una única escena genérica (Pickup.tscn) cuyo nodo raíz sea un Area2D.

Esta escena expone una variable de tipo Item y se encarga exclusivamente de gestionar la colisión y la reproducción de audio y/o animaciones.

@tool
class_name Pickup extends Area2D

@export var item: Item = null: set = set_item

@onready var _sprite_2d: Sprite2D = %Sprite2D
@onready var _audio_stream_player: AudioStreamPlayer = %AudioStreamPlayer

func _ready() -> void:
	# [...] Lógica de animaciones en idle, si aplica
	
	body_entered.connect(func (body: Node2D) -> void:
		if body is Player:
			# No nos importa qué ítem es, solo sabemos que cumple el contrato
			item.use_with(body) 
			
			set_deferred("monitoring", false)
			_audio_stream_player.play()
			queue_free()
	)

Mejorar la DX (Developer Experience): Avisos en el editor

Para mejorar la experiencia de desarrollo de cara a mi “yo del futuro” o colaboradores, una buena práctica es integrar alertas directas en el editor/inspector.

Añadiendo la anotación @tool al principio del script de Pickup, obligamos a Godot a ejecutar el código incluso en el editor. Esto permite hacer un override de la función _get_configuration_warnings() para que el propio inspector nos lance un aviso (el típico ⚠️ en el árbol de nodos de la escena) si arrastramos un cofre o un ítem al nivel y nos olvidamos de asignarle un recurso en sus propiedades.

func _get_configuration_warnings() -> PackedStringArray:
	var warnings := PackedStringArray()
	if null == item:
		warnings.append("Cuidado: No has asignado ningún recurso Item a este pickup.")
	return warnings

Aplicar estos principios tradicionales de desarrollo de software al árbol de escenas de Godot mejora la escalabilidad y mantenibilidad, evitando construir de forma desordenada y frágil a favor de algo modular y robusto.