Para entender la utilidad de las PackedScene (escena empaquetada), es fundamental comprender primero qué definimos como una "escena" en Godot y cómo se almacenan.

(Si necesitas un repaso profundo de los conceptos básicos, puedes consultarlos en la documentación o mi libro anterior, donde abordamos esto a fondo.)

En definitiva, la importancia de las escenas a la que quiero apuntar viene muy relacionada con el concepto de "instanciar". Repasaremos brevemente su lógica, ya que es la base para el uso de PackedScene.


Escenas, Moldes e Instanciación

Imaginemos que necesitamos un spawn de rocas que aparecerán cada 2 segundos en la parte superior de la pantalla y caerán. Nuestro personaje debe esquivarlas.

Para que el spawn pueda crear rocas, necesitamos un "modelo" de la roca base. A este proceso de crear copias a partir de un modelo lo llamamos instanciar.

Instanciar nos permite tomar una escena guardada como si fuera un "molde" y crear una copia activa en nuestro juego.

  • El Molde (La Escena Guardada): Suele ser un archivo (.tscn o similar) almacenado en una carpeta de tu proyecto. No está presente en el árbol de jerarquías del nivel actual, solo se usa como referencia.
  • La Copia Activa (La Instancia): Es la copia funcional que aparecerá en tu nivel, se agregará al árbol de jerarquías y participará activamente en la lógica del juego.

¿Dónde entra PackedScene?

PackedScene es un tipo de variable clave en Godot que te permitirá guardar la referencia de esa escena que quieres usar como molde. Al ser un archivo guardado, debemos indicarle la ruta o dirección para que pueda encontrarlo.

Podríamos hacerlo de la forma más común, sin declarar explícitamente el tipo PackedScene y dejando que Godot infiera el tipo de dato:

GDScript
var player1 = preload("res://scenes/player_1.tscn")

En este ejemplo:

  1. Se crea la variable player1.
  2. Se usa la función preload() para precargar el recurso (la escena).
  3. Se pasa la ruta del archivo de escena (.tscn).

Hemos obtenido el molde del player, listo para crear uno o varios players a partir de él (útil para respawn, multijugador o posiciones dinámicas).


Instanciando la Copia Activa

Una vez que tienes la referencia (el molde) guardada en tu variable, el proceso de instanciar y agregar al juego es sencillo:

1. Crear el Clon (Instanciar)

Utilizamos el método instantiate() sobre la variable que contiene la referencia:

GDScript
var newPlayer = player1.instantiate()

newPlayer es ahora el clon activo, pero aún no es parte de la escena.

2. Agregar al Árbol de Jerarquías

Debemos agregarlo como hijo de algún nodo que ya exista en el nivel.

GDScript
add_child(newPlayer) 

Esto agrega el clon como hijo del objeto que está ejecutando el script (el que llamó a add_child()).

Si quieres que sea hijo de otro nodo específico, usa el operador $ o get_node():

GDScript
$OtroNodo.add_child(newPlayer)

Lo importante es que la variable player1 (en realidad de tipo PackedScene) guarda la referencia al archivo de escena player_1.tscn, permitiendo crear estos "clones vivos".


Aplicando al Ejemplo de las Rocas

Volviendo a nuestro ejemplo, haríamos lo siguiente:

  • Crear el Molde de Roca: Creamos una escena de roca (por ejemplo, un RigidBody2D con su Sprite2D), y la guardamos como roca.tscn en la ruta res://scenes/enemies/roca.tscn.
  • Crear la Referencia (PackedScene):

GDScript
var rocaRef = preload("res://scenes/enemies/roca.tscn")
  • Crear Copias Múltiples: Podemos instanciar tantas copias como queramos:

GDScript
for i in 12:
    var newRoca = rocaRef.instantiate()
    add_child(newRoca)

El Desafío de la Posición

En el ejemplo anterior, hemos creado 12 rocas... pero todas se crearán en la posición por defecto, compartiendo el mismo punto y generando una respuesta física inadecuada.

Cuando creamos un objeto, debemos modificar sus propiedades si deseamos un comportamiento dinámico. En este caso, lo más conveniente es modificar la posición de cada roca para que aparezcan separadas y en la parte superior del mapa, pero también podrías querer modificar su rotación, escala, o cualquier otro dato pertinente.

Podríamos intentar modificar la posición así:

GDScript
newRoca.global_position = Vector2(0, 15)

Pero... ¿sabemos si 15 es la coordenada Y correcta para que aparezca por encima del mapa sin estar testeando manualmente?

¿Cómo encontrar una forma conveniente y dinámica para manejar estas posiciones?. Lo revelamos en el próximo capítulo.

Este es un extracto de mi libro "La Biblia de Godot (Nivel 2)" que podes encontrar clickeando la siguiente imagen: