Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Recursos
Nós e recursos
Até agora, focamos muito na classe de Nós no Godot, já que a maioria dos comportamentos e funcionalidades do motor são implementados através deles. Existe outro tipo de dados que é igualmente importante: Recurso.
Nós dão funcionalidade: eles desenham sprites, modelos 3D, simulam física, organizam a interface do usuário, etc. Recursos são containers de dados. Eles não fazem nada sozinhos: ao invés disso, os nós usam os dados contidos em recursos.
Qualquer coisa que o Godot salve ou carregue do disco é um recurso. Seja uma cena (um arquivo .tscn ou .scn), uma imagem, um script... Aqui estão alguns exemplos de Resource:
Quando um recurso é carregado do disco, é carregado só uma vez. Se houver uma cópia desse recurso já carregado na memória, tentar carregar o recurso novamente retornará a mesma cópia várias vezes. Como recursos são apenas contêineres de dados, não é necessário duplicá-los.
Todos os objetos em Godot (Nós, Recursos ou qualquer outra coisa) podem exportar propriedades. Há muitos tipos de Propriedades, como String, inteiro, Vector2, etc., e qualquer desses tipos pode virar um recurso. Isso significa que os nós e os recursos podem conter recursos como propriedades:
Externo vs embutido
Existem duas maneiras de salvar recursos. Pode ser:
Externo a uma cena, salvo no disco como arquivos individuais.
Embutido, salvo dentro do arquivo
.tscnou.scnao qual estão anexados.
Para ser mais específico, aqui está uma Texture2D em um nó Sprite2D:
Clicar na pré-visualização do recurso nos permite ver as propriedades do recurso.
A propriedade caminho nos diz de onde o recurso vem. Nesse caso ele vem de uma imagem PNG chamada robi.png. Quando o recurso vem de um arquivo como esse, ele é um recurso externo. Se você apagar o caminho ou esse caminho estiver vazio, ele se transforma em um recurso embutido.
A mudança entre recursos embutidos e externos acontece quando você salva a cena. No exemplo acima, se você apaga o caminho "res://robi.png" e salva, o Godot vai salvar a imagem dentro do arquivo de cena .tscn.
Nota
Even if you save a built-in resource, when you instantiate a scene multiple times, the engine will only load one copy of it.
Carregando recursos a partir do código
Existem duas maneiras de carregar recursos por código. Primeiro, você pode usar a função load() a qualquer 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;
}
Você também pode usar preload para recursos. Ao contrário de load, esta função lerá o arquivo do disco e carregará em tempo de compilação. Como resultado, você não pode chamar preload com um caminho variável: você precisa usar uma string constante.
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.
Carregando cenas
Cenas também são recursos, mas há uma pegadinha. Cenas salvas no disco são recursos do tipo PackedScene. A cena é empacotada dentro de um Resource.
Para obter uma instância da cena, você deve usar o método PackedScene.instantiate().
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);
}
Esse método cria os nós na hierarquia da cena, configura-os, e retorna o nó raiz da cena, que pode ser adicionado como filho de qualquer outro nó.
A abordagem tem várias vantagens. Como a função PackedScene.instantiate() é rápida, você pode criar novos inimigos, balas, efeitos, etc., sem precisar carregá-los novamente do disco a cada vez. Lembre-se de que, como sempre, imagens, malhas, etc., são todas compartilhadas entre as instâncias da cena.
Liberando recursos
Quando um Resource não está mais em uso, ele se libera automaticamente. Como, na maioria dos casos, os Recursos estão contidos em Nós, quando você libera um nó, o motor libera todos os recursos que ele possui também, se nenhum outro nó os usar.
Criando seus próprios recursos
Como qualquer Objeto no Godot, os usuários também podem criar scripts de Recursos. Scripts de recursos herdam a capacidade de traduzir livremente entre propriedades de objeto e dados serializados de texto ou binários (*.tres, *.res). Eles também herdam o gerenciamento de memória por contagem de referências do tipo RefCounted.
Isso traz muitas vantagens distintas sobre estruturas de dados alternativas, como JSON, CSV ou arquivos TXT personalizados. Os usuários só podem importar esses ativos como um Dictionary (JSON) ou como um FileAccess para analisar. O que diferencia os Recursos é a herança dos recursos de Object, RefCounted e Resource:
Eles podem definir constantes, portanto, constantes de outros campos ou objetos de dados não são necessárias.
Eles podem definir métodos, incluindo métodos setter / getter para propriedades. Isso permite abstração e encapsulamento dos dados subjacentes. Se a estrutura do script Resource precisar ser alterada, o jogo usando o recurso também não precisará ser alterado.
Eles podem definir sinais, para que os Recursos possam acionar respostas a alterações nos dados que eles gerenciam.
Eles definiram propriedades, portanto, os usuários sabem 100% que seus dados existirão.
A serialização automática e desserialização do recurso é um recurso interno do Godot Engine. Os usuários não precisam implementar a lógica personalizada para importar/exportar os dados de um arquivo de recurso.
Os recursos podem até serializar os sub-recursos recursivamente, o que significa que os usuários podem criar estruturas de dados ainda mais sofisticadas.
Os usuários podem salvar Recursos como arquivos de texto compatíveis com controle de versão (*.tres). Ao exportar um jogo, o Godot serializa arquivos de recurso como arquivos binários (*.res) para maior velocidade e compressão.
O Inspetor do Godot Engine processa e edita arquivos de recursos prontos para uso. Dessa forma, os usuários geralmente não precisam implementar lógica personalizada para visualizar ou editar seus dados. Para fazer isso, clique duas vezes no arquivo de recursos na estação FileSystem ou clique no ícone da pasta no Inspetor e abra o arquivo na caixa de diálogo.
Eles podem estender outros tipos de recurso, além do Resource base.
Godot facilita a criação de recursos personalizados no Inspetor.
Crie um novo objeto de Recurso no Inspetor. Isso pode até ser um tipo que deriva de Recurso, desde que seu script esteja estendendo esse tipo.
Defina a propriedade
scriptno Inspetor como o seu script.
O Inspetor agora exibirá as propriedades personalizadas do seu script de Recurso. Se alguém editar esses valores e salvar o recurso, o Inspetor serializa as propriedades personalizadas também! Para salvar um recurso do Inspetor, clique no ícone de salvar na parte superior do Inspetor e selecione "Salvar" ou "Salvar Como...".
Se a linguagem do script suportar classes de script, então isso agiliza o processo. Definir um nome para o seu script apenas o adicionará à caixa de diálogo de criação do Inspetor. Isso adicionará automaticamente seu script ao objeto de Recurso que você criar.
Vejamos alguns exemplos. Crie um Resource e nomeie-o como bot_stats. Ele deve aparecer na sua aba de arquivos com o nome completo bot_stats.tres. Sem um script, ele é inútil, então vamos adicionar alguns dados e lógica! Anexe um script a ele chamado bot_stats.gd (ou apenas crie um novo script e depois arraste-o para ele).
Nota
Para fazer com que a nova classe de recurso apareça na GUI de Criação de Recurso, você precisa fornecer um nome de classe (class_name) para o GDScript, ou usar o atributo [GlobalClass] no C#.
class_name BotStats
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
{
[GlobalClass]
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>();
}
}
}
Agora, crie um CharacterBody3D, nomeie-o como Bot e adicione o seguinte script a ele:
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'.
}
}
}
}
Agora, selecione o nó CharacterBody3D que nomeamos como bot e arraste e solte o recurso bot_stats.tres no Inspetor. Ele deve imprimir 10! Obviamente, essa configuração pode ser usada para recursos mais avançados do que este, mas contanto que você realmente entenda como tudo funcionou, você deve decifrar todo o resto relacionado a Resources.
Nota
Scripts de Recursos são semelhantes aos ScriptableObjects do Unity. O Inspetor oferece suporte integrado para recursos personalizados. Se desejado, no entanto, os usuários podem até projetar seus próprios scripts de ferramenta baseados em Control e combiná-los com um EditorPlugin para criar visualizações e editores personalizados para seus dados.
As DataTables e CurveTables do Unreal Engine também são fáceis de recriar com scripts de Recursos. DataTables são uma String mapeada para uma struct personalizada, semelhante a um Dicionário mapeando uma String para um script de Recurso personalizado secundário.
# 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;
[GlobalClass]
public partial class BotStatsTable : Resource
{
private Godot.Collections.Dictionary<string, BotStats> _stats = new Godot.Collections.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);
}
}
Em vez de incorporar os valores do dicionário diretamente no código, também se poderia, alternativamente:
Importe uma tabela de valores de uma planilha e gere esses pares chave-valor.
Projete uma visualização dentro do editor e crie um plugin que a adicione ao Inspetor quando você abrir esses tipos de Recursos.
CurveTables são a mesma coisa, exceto mapeadas para um Array de valores float ou um objeto de recurso Curve/Curve2D.
Aviso
Lembre-se de que arquivos de recurso (*.tres/*.res) armazenam internamente o caminho do script que utilizam. Ao serem carregados, eles buscam e carregam esse script como uma extensão de seu próprio tipo. Isso significa que tentar atribuir uma classe interna de um script (ou seja, usando a palavra-chave class no GDScript) não funcionará; o Godot não serializará corretamente as propriedades personalizadas da classe interna do script.
No exemplo abaixo, o Godot carregaria o script Node, verificaria que ele não estende Resource e, então, determinaria que o carregamento do script falhou para o objeto Resource, uma vez que os tipos são incompatíveis.
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
{
[GlobalClass]
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");
}
}