Las escenas y scripts de Godot son clases

En Godot, tanto las escenas como los scripts pueden ser el equivalente a las clases en un lenguaje de programación orientado a objetos. La principal diferencia es que las escenas son código declarativo, mientras que los scripts pueden contener código imperativo.

Como resultado, muchas buenas prácticas en Godot se reducen a aplicar principios de diseño orientado a objetos a las escenas, nodos o scripts que forman tu juego.

Esta guía explica cómo funcionan los scripts y las escenas en el núcleo del motor, para ayudarte a tener una idea de cómo funciona Godot por dentro, y ayudarte a que entiendas mejor de dónde vienen algunas buenas prácticas de esta serie.

Dando sentido a las clases en Godot

El motor de Godot proporciona clases incorporadas como Nodo. Los tipos creados por el usuario no son técnicamente clases. En cambio, son recursos que dan al motor una serie de inicializaciones a realizar en una de las clases incorporadas del motor.

Las clases internas de Godot tienen métodos que registran los datos de una clase mediante una ClassDB. Esta base de datos proporciona acceso en tiempo de ejecución a información de la clase. ClassDB contiene información sobre las clases como:

  • Propiedades
  • métodos
  • Constantes
  • señales

Esta ClassDB es lo que los objetos verifican cuando realizan una operación como acceder a una propiedad o llamar un método. ClassDB comprueba los registros de la base de datos y los registros de los tipos base del objeto para ver si el objeto soporta la operación.

En el lado del motor, cada clase define una función _bind_methods() estática que describe qué contenido de C++ registra en la base de datos y cómo. Cuando usas el motor, puedes ampliar los métodos, propiedades y señales disponibles de la ClassDB vinculando un Script al nodo.

Los objetos comprueban sus scripts vinculados antes que la base de datos. Esta es la razón por la cual los scripts pueden redefinir métodos incorporados. Si un script define un método _get_property_list(), Godot adjunta esta información a la lista de propiedades que el objeto extrae de la ClassDB. Lo mismo sucede con otro código declarativo.

Incluso los scripts que no heredan de un tipo incorporado, como por ejemplo scripts que no empiezan con la palabra clave extends, implícitamente heredan de la clase base Reference del motor. Esto permite al objeto diferir al contenido del script donde la lógica del motor considere apropiado.

Nota

Como resultado, puedes instanciar scripts sin la palabra clave extends mediante código, pero no puedes vincularlos a un Node

Rendimiento del scripting y PackedScene

A medida que crece el tamaño de los objetos, el tamaño necesario de los scripts para crearlos crece mucho, mucho más. Crear jerarquías de nodos demuestra esto. La lógica de cada nodo individual podría ser de varios cientos de líneas de código.

Veamos un sencillo ejemplo de crear un solo Node como hijo. El código a continuación crea un nuevo Node, cambia su nombre, asigna un script al mismo, establece su futuro padre como su propietario para que se guarde en disco junto a él, y finalmente lo añade como un hijo del nodo Main:

# Main.gd
extends Node

func _init():
    var child = Node.new()
    child.name = "Child"
    child.script = preload("Child.gd")
    child.owner = self
    add_child(child)
using System;
using Godot;

namespace ExampleProject
{
    public class Main : Resource
    {
        public Node Child { get; set; }

        public Main()
        {
            Child = new Node();
            Child.Name = "Child";
            Child.Script = (Script)ResourceLoader.Load("child.gd");
            Child.Owner = this;
            AddChild(Child);
        }
    }
}

Código de script como éste es mucho más lento que código C++ del lado del motor. Cada cambio hace una llamada separada a la API de scripting que conlleva muchas búsquedas en el back-end para encontrar la lógica a ejecutar.

Las escenas ayudan a evitar este problema de rendimiento. PackedScene, el tipo base del que heredan las escenas, son recursos que usan datos serializados para crear objetos. El motor puede procesar escenas por lotes en el back-end y proporcionar mucho mejor rendimiento que los scripts.

Escenas y scripts son objetos

¿Por qué esto es importante para la organización de las escenas? Porque las escenas son objetos. A menudo se empareja una escena con un nodo raíz con script que hace uso de los sub-nodos. Esto significa que la escena es a menudo una extensión del código declarativo del script.

El contenido de una escena ayuda a definir:

  • Qué nodos están disponibles al script
  • Cómo están organizados
  • Cómo se inicializan
  • Qué conexiones de señales tienen entre ellos

Varios principios orientados a objetos que se aplican a código escrito también se aplican a las escenas.

La escena es siempre una extensión del script vinculado a su nodo raíz. Puedes ver todos los nodos que contiene como parte de una sola clase.

La mayoría de los consejos y técnicas explicados en esta serie se basarán en esto.