Up to date
This page is up to date for Godot 4.2
.
If you still find outdated information, please open an issue.
Recursos¶
Nodos y recursos¶
Hasta ahora, nos hemos centrado en la clase Node de Godot , ya que es la que usarás para programar comportamientos y de la que dependen la mayoría de las características del motor. Hay otro tipo de datos que es igualmente importante: Resource.
Los Nodes te dan funcionalidad: Dibujan sprites, modelos 3D, simulan físicas, organizan interfaces gráficas, etc. Los Resources son data containers. Ellos no hacen nada por su cuenta: en su lugar, los nodos usan los datos contenidos en los Resources.
Todo lo que Godot guarde o cargue desde el disco es un recurso. Ya sea una escena (archivo .tscn
o .scn
), una imagen, un script... Estos son algunos ejemplos de Resource :
Cuando el motor carga un recurso desde el disco, siempre se carga una sola vez. Esto significa que, si hay una copia de ese recurso ya cargado en la memoria, intentar cargar el recurso de nuevo devolverá la misma copia una y otra vez. Esto se corresponde con el hecho de que los recursos son sólo contenedores de datos, por lo que no es necesario duplicarlos.
Cada objeto, sea Node o Resource, puede exportar propiedades. Existen muchos tipos de proiedades como un String, integer, Vector2, etc., y cualquiera de esos tipos puede ser un recurso. Esto significa que tanto los Node como los Resources pueden contener Resources como propiedades:
Externo vs built-in¶
Hay dos formas de grabar Resources. Estas pueden ser:
External a una escena, guardada en el disco como archivos individuales.
Built-in, guardado dentro del archivo
.tscn
o.scn
al que están adjuntos.
To be more specific, here's a Texture2D in a Sprite2D node:
Clicking the resource preview allows us to view the resource's properties.
La propiedad "path" nos dice de donde proviene el recurso. En este caso, proviene de una imagen PNG llamada robi.png
. Cuando el recurso proviene de un archivo como este, es un recurso externo. Si borra la ruta o esta ruta está vacía, se convierte en un recurso incorporado.
El cambio entre recursos incorporados (built-in) y externos se produce al guardar la escena. En el ejemplo anterior, si borras la ruta "res://robi.png"
y guardas, Godot guardará la imagen dentro del archivo de escena .tscn.
Nota
Incluso si guardas un recurso incorporado, cuando hagas múltiples instancias de una escena, el motor sólo cargará una copia del recurso.
Cargando recursos desde código¶
Hay dos maneras de cargar recursos desde el código. La primera es usando la función load()
en cualquier momento:
func _ready():
# Godot loads the Resource when it reads this very line.
var imported_resource = load("res://robi.png")
$sprite.texture = imported_resource
public override void _Ready()
{
// Godot loads the Resource when it executes this line.
var texture = GD.Load<Texture>("res://Robi.png");
var sprite = GetNode<Sprite2D>("sprite");
sprite.Texture = texture;
}
You can also preload
resources. Unlike load
, this function will read the
file from disk and load it at compile-time. As a result, you cannot call preload
with a variable path: you need to use a constant string.
func _ready():
# Godot loads the resource at compile-time
var imported_resource = preload("res://robi.png")
get_node("sprite").texture = imported_resource
// 'preload()' is unavailable in C Sharp.
Cargando escenas¶
Scenes are also resources, but there is a catch. Scenes saved to disk are resources of type PackedScene. The scene is packed inside a Resource.
To get an instance of the scene, you have to use the PackedScene.instantiate() method.
func _on_shoot():
var bullet = preload("res://bullet.tscn").instantiate()
add_child(bullet)
private PackedScene _bulletScene = GD.Load<PackedScene>("res://Bullet.tscn");
private void OnShoot()
{
Node bullet = _bulletScene.Instantiate();
AddChild(bullet);
}
Este método crea nodos en la estructura de la escena, los configura (asigna las propiedades) y retorna el nodo raíz de la escena, el cual puede ser agregado como hijo a cualquier otro nodo.
The approach has several advantages. As the PackedScene.instantiate() function is fast, you can create new enemies, bullets, effects, etc. without having to load them again from disk each time. Remember that, as always, images, meshes, etc. are all shared between the scene instances.
Liberando recursos¶
When a Resource is no longer in use, it will automatically free itself. Since, in most cases, Resources are contained in Nodes, when you free a node, the engine frees all the resources it owns as well if no other node uses them.
Creando tus propios Resources¶
Like any Object in Godot, users can also script Resources. Resource scripts inherit the ability to freely translate between object properties and serialized text or binary data (*.tres, *.res). They also inherit the reference-counting memory management from the RefCounted type.
This comes with many distinct advantages over alternative data structures, such as JSON, CSV, or custom TXT files. Users can only import these assets as a Dictionary (JSON) or as a FileAccess to parse. What sets Resources apart is their inheritance of Object, RefCounted, and Resource features:
Pueden definir constantes, así que no se necesitan constantes de otros campos de datos u objetos.
Pueden definir métodos, incluidos los métodos de setter/getter de propiedades. Esto permite la abstracción y la encapsulación de los datos subyacentes. Si la estructura del script de recurso necesita cambiar, el juego que usa el recurso no necesita cambiar también.
Pueden definir señales, por lo que los recursos pueden desencadenar respuestas a los cambios en los datos que administran.
Tienen propiedades definidas, por lo que los usuarios saben al 100% que sus datos existirán.
La auto-serialización y deserialización de recursos es una característica incorporada del motor de Godot. Los usuarios no necesitan implementar una lógica personalizada para importar / exportar los datos de un archivo de recursos.
Los recursos pueden incluso serializar sub-recursos de forma recursiva, lo que significa que los usuarios pueden diseñar estructuras de datos aún más sofisticadas.
Los usuarios pueden guardar Recursos como archivos de texto amigables con el control de versiones (*.res). Al exportar un juego, Godot serializa los archivos de recursos como archivos binarios (*.res) para aumentar la velocidad y la compresión.
El inspector de Godot procesa y edita los archivos de recursos de forma inmediata. Como tal, los usuarios a menudo no necesitan implementar una lógica personalizada para ver o editar sus datos. Para hacerlo, haga doble clic en el archivo de recursos en el panel FileSystem o haga clic en el icono de carpeta en el Inspector y abra el archivo en el cuadro de diálogo.
Pueden extender ** otros ** tipos de recursos además del recurso base.
Godot facilita la creación de recursos personalizados en el Inspector.
Cree un objeto de recurso simple en el inspector. Este puede ser incluso un tipo que derive el recurso, siempre y cuando su script esté extendiendo ese tipo.
Establece la propiedad
script
en el Inspector para que sea tu script.
El inspector ahora mostrará las propiedades personalizadas de su script de recursos. Si uno edita esos valores y guarda el recurso, ¡el Inspector serializa las propiedades personalizadas también! Para guardar un recurso del Inspector, haga clic en el menú de herramientas del Inspector (arriba a la derecha) y seleccione "Save" o "Save As...".
Si el lenguaje del script admite clases de script, esto agiliza el proceso. Definir un nombre para tu script automáticamente lo agregará al cuadro de diálogo de creación del Inspector. Esto agregará automáticamente tu script al objeto Resource que creas.
Let's see some examples.
Create a Resource and name it bot_stats
.
It should appear in your file tab with the full name bot_stats.tres
.
Without a script, it's useless, so let's add some data and logic!
Attach a script to it named bot_stats.gd
(or just create a new script, and then drag it to it).
extends Resource
@export var health: int
@export var sub_resource: Resource
@export var strings: PackedStringArray
# Make sure that every parameter has a default value.
# Otherwise, there will be problems with creating and editing
# your resource via the inspector.
func _init(p_health = 0, p_sub_resource = null, p_strings = []):
health = p_health
sub_resource = p_sub_resource
strings = p_strings
// BotStats.cs
using Godot;
namespace ExampleProject
{
public partial class BotStats : Resource
{
[Export]
public int Health { get; set; }
[Export]
public Resource SubResource { get; set; }
[Export]
public string[] Strings { get; set; }
// Make sure you provide a parameterless constructor.
// In C#, a parameterless constructor is different from a
// constructor with all default values.
// Without a parameterless constructor, Godot will have problems
// creating and editing your resource via the inspector.
public BotStats() : this(0, null, null) {}
public BotStats(int health, Resource subResource, string[] strings)
{
Health = health;
SubResource = subResource;
Strings = strings ?? System.Array.Empty<string>();
}
}
}
Now, create a CharacterBody3D, name it Bot
, and add the following script to it:
extends CharacterBody3D
@export var stats: Resource
func _ready():
# Uses an implicit, duck-typed interface for any 'health'-compatible resources.
if stats:
stats.health = 10
print(stats.health)
# Prints "10"
// Bot.cs
using Godot;
namespace ExampleProject
{
public partial class Bot : CharacterBody3D
{
[Export]
public Resource Stats;
public override void _Ready()
{
if (Stats is BotStats botStats)
{
GD.Print(botStats.Health); // Prints '10'.
}
}
}
}
Now, select the CharacterBody3D node which we named bot
, and drag&drop the bot_stats.tres
resource onto the Inspector. It should print 10! Obviously, this setup can be used for more advanced features than this, but as long you really understand how it all worked, you should figure out everything else related to Resources.
Nota
Los scripts de recursos son similares a los ScriptableObjects de Unity. El Inspector proporciona soporte integrado para recursos personalizados. Si así lo desean, los usuarios pueden incluso diseñar sus propios scripts de herramientas basadas en Control y combinarlos con un EditorPlugin para crear visualizaciones y editores personalizados para sus datos.
Unreal Engine's DataTables and CurveTables are also easy to recreate with Resource scripts. DataTables are a String mapped to a custom struct, similar to a Dictionary mapping a String to a secondary custom Resource script.
# bot_stats_table.gd
extends Resource
const BotStats = preload("bot_stats.gd")
var data = {
"GodotBot": BotStats.new(10), # Creates instance with 10 health.
"DifferentBot": BotStats.new(20) # A different one with 20 health.
}
func _init():
print(data)
using Godot;
public partial class BotStatsTable : Resource
{
private Godot.Dictionary<string, BotStats> _stats = new Godot.Dictionary<string, BotStats>();
public BotStatsTable()
{
_stats["GodotBot"] = new BotStats(10); // Creates instance with 10 health.
_stats["DifferentBot"] = new BotStats(20); // A different one with 20 health.
GD.Print(_stats);
}
}
En lugar de simplemente definir los valores del Diccionario en una línea, también se puede, opcionalmente:
Import a table of values from a spreadsheet and generate these key-value pairs.
Design a visualization within the editor and create a plugin that adds it to the Inspector when you open these types of Resources.
Las CurveTables son la misma cosa, excepto que se asignan a un Array de valores flotantes o a un objeto de recurso Curve/Curve2D.
Advertencia
Tenga en cuenta que los archivos de recursos (*.tres/*.res) almacenarán la ruta del script que usan en el archivo. Cuando se carguen, obtendrán y cargarán este script como una extensión de su tipo. Esto significa que tratar de asignar una subclase, es decir, una clase interna de un script (como usar la palabra clave class
en GDScript) no funcionará. Godot no serializará correctamente las propiedades personalizadas en la subclase del script.
En el siguiente ejemplo, Godot cargaría el script Node
, vería que no extiende Resource
, y luego determinaría que el script no se pudo cargar para el objeto Resource ya que los tipos son incompatibles.
extends Node
class MyResource:
extends Resource
@export var value = 5
func _ready():
var my_res = MyResource.new()
# This will NOT serialize the 'value' property.
ResourceSaver.save(my_res, "res://my_res.tres")
using Godot;
public partial class MyNode : Node
{
public partial class MyResource : Resource
{
[Export]
public int Value { get; set; } = 5;
}
public override void _Ready()
{
var res = new MyResource();
// This will NOT serialize the 'Value' property.
ResourceSaver.Save(res, "res://MyRes.tres");
}
}