Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

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.

Anything Godot saves or loads from disk is a resource. Be it a scene (a .tscn or an .scn file), an image, a script... Here are some Resource examples:

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:

../../_images/nodes_resources.webp

Externo vs embutido

Existem duas maneiras de salvar recursos. Pode ser:

  1. Externo a uma cena, salvo no disco como arquivos individuais.

  2. Embutido, salvo dentro do arquivo .tscn ou .scn ao qual estão anexados.

To be more specific, here's a Texture2D in a Sprite2D node:

../../_images/spriteprop.webp

Clicking the resource preview allows us to view the resource's properties.

../../_images/resourcerobi.webp

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

Mesmo se você salvar um recurso interno, quando você instancia uma cena várias vezes, o motor carregará apenas uma cópia dela.

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

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

Carregando cenas

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)

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ó.

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.

Criando seus próprios recursos

Como qualquer Objeto em Godot, os usuários também podem criar scripts em Recursos. Scripts de recursos herdam a capacidade de mover-se livremente entre propriedades de objetos e texto serializado ou dados binários (*.tres, *.res). Eles também herdam o gerenciamento de memória de contagem de referência do tipo de referência.

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:

  • 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 amigáveis ao controle de versões (*. Tres). Ao exportar um jogo, Godot serializa os arquivos de recursos como arquivos binários (*. Res) para maior velocidade e compactaçã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 recursos além do recurso base.

Godot facilita a criação de recursos personalizados no Inspetor.

  1. Crie um objeto de recurso simples no Inspetor. Isso pode até ser um tipo que deriva Resource, desde que seu script esteja estendendo esse tipo.

  2. Defina a propriedade `` script`` no Inspector como seu script.

O inspetor agora exibirá as propriedades personalizadas do script de recursos. Se você editar esses valores e salvar o recurso, o inspetor serializará as propriedades personalizadas também! Para salvar um recurso do Inspetor, clique no menu de ferramentas do Inspetor (canto superior direito) e selecione "Salvar" ou "Salvar como ...".

If the script's language supports script classes, then it streamlines the process. Defining a name for your script alone will add it to the Inspector's creation dialog. This will auto-add your script to the Resource object you create.

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

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"

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

Scripts de recursos são semelhantes aos ScriptableObjects da Unity. O Inspector fornece suporte interno para recursos personalizados. Se desejado, os usuários podem até criar seus próprios scripts de ferramentas baseados em Control e combiná-los com um: ref: EditorPlugin <class_EditorPlugin> para criar visualizações e editores personalizados para seus dados.

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)

Instead of inlining the Dictionary values, one could also, alternatively:

  1. Import a table of values from a spreadsheet and generate these key-value pairs.

  2. Design a visualization within the editor and create a plugin that adds it to the Inspector when you open these types of Resources.

CurveTables são a mesma coisa, mas mapeadas em uma matriz de valores float ou um objeto de recurso :ref: Curve <class_Curve> /: ref: Curve2D <class_Curve2D>.

Aviso

Esteja ciente de que os arquivos de recursos (*.tres / *.res) armazenarão o caminho do script que eles usam no arquivo. Quando carregados, eles buscarão e carregarão esse script como uma extensão do tipo. Isso significa que tentar atribuir uma subclasse, ou seja, uma classe interna de um script (como usar a palavra-chave `` class`` no GDScript) não funcionará. Godot não serializará as propriedades personalizadas na subclasse do script adequadamente.

No exemplo abaixo, Godot carregaria o script `` Node``, veria que ele não estende `` Resource`` e determinará que o script falhou ao carregar o objeto Resource, pois 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")