Up to date

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

Ressources

Nœuds et ressources

Jusqu'à présent, les Nœuds ont été le type de donnée le plus important dans Godot car la plupart des comportements et des fonctionnalités du moteur sont implémentés par leur biais. Il y a un autre type de donnée qui est tout aussi important : Ressource.

Les nœuds vous offrent des fonctionnalités : ils dessinent des sprites, des modèles 3D, simulent des propriétés physiques, organisent une interface utilisateur, etc. Les ressources sont des conteneurs de données. Elles ne font rien par elles-mêmes et les nœuds utilisent les données qu'elles contiennent.

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:

Quand une ressource est chargée depuis le disque dur, elle est chargée une seule fois. Cela signifie, si il y a une copie de cette ressource déjà chargée en mémoire, essayer de charger à nouveau cette ressource retournera la même copie encore et encore. Cela correspond au fait que les ressources sont justes des conteneurs de données, donc il n'y a pas besoin de les dupliquer.

Typiquement, chaque objet, un Nœud ou une Ressource, peuvent exporter des propriétés. Il y a de nombreux de types différents comme une chaîne de caractère, un entier, Vector2, etc... et n'importe lequel de ces types peut devenir une ressource. Cela veut dire que les nœuds et les ressources peuvent contenir des ressources comme propriétés :

../../_images/nodes_resources.webp

Externe vs intégré

Il y a 2 possibilités pour sauvegarder les ressources. Vous pouvez :

  1. Externe à une scène, enregistrés sur le disque en tant que fichiers individuels.

  2. Built-in (intégrées), enregistrées dans le fichier .tscn ou le fichier .scn auquel elles sont attachés.

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

La propriété chemin nous indique d'où provient la ressource. Dans ce cas, elle provient d'une image PNG appelée robi.png. Lorsque la ressource provient d'un fichier comme celui-ci, il s'agit d'une ressource externe. Si vous effacez le chemin ou que ce chemin est vide, il devient une ressource intégrée.

Le basculement entre les ressources intégrées et externes se produit lorsque vous enregistrez la scène. Dans l'exemple ci-dessus, si vous effacez le chemin "res://robi.png" et que vous sauvegardez, Godot sauvegardera l'image dans le fichier de scène .tscn.

Note

Même si vous enregistrez une ressource intégrée, lorsque vous créez une scène plusieurs fois, le moteur n'en charge qu'une copie.

Chargement de ressources à partir du code

Il existe deux manières de charger des ressources depuis un code. Tout d’abord, vous pouvez utiliser la fonction load() à tout moment :

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

Chargement de scènes

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)

Cette méthode crée les nœuds dans la hiérarchie de la scène, les configure (définit toutes les propriétés) et retourne le nœud racine de la scène qui peut être ajouté comme enfant à n'importe quel autre nœud.

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.

Libérer des ressources

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.

Créer vos propres ressources

Comme tout Object de Godot, les utilisateurs peuvent également scripter les Resources. Les scripts de Resource héritent de la possibilité de traduire librement les propriétés d'objet vers le texte sérialisé ou les données binaires (*.tres, *.res) et inversement. Ils héritent également de la gestion de la mémoire par comptage de référence du type Référence.

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:

  • Elles peuvent définir des constantes. Ainsi, les constantes depuis d'autres champs de données ou objets ne sont pas nécessaires.

  • Elles peuvent définir des méthodes, y compris des méthodes setter/getter pour les propriétés. Cela permet l’abstraction et l’encapsulation des données sous-jacentes. Si la structure du script de ressource doit être modifiée, le jeu utilisant la Resource, lui, ne nécessite pas de changement.

  • Elles peuvent définir des signaux afin que les Resources puissent déclencher des réactions aux modifications des données qu’elles gèrent.

  • Elles ont des propriétés définies, de sorte que les utilisateurs savent à 100% que leurs données existent.

  • L’auto-sérialisation et la dé-sérialisation de Resource est une fonctionnalité intégrée du moteur Godot. Les utilisateurs n'ont pas besoin d'implémenter une logique personnalisée pour importer/exporter les données d'un fichier de ressources.

  • Les Resources peuvent même sérialiser les sous-Resources de manière récursive, ce qui signifie que les utilisateurs peuvent concevoir des structures de données encore plus sophistiquées.

  • Les utilisateurs peuvent enregistrer des Resources sous forme de fichiers textes compatible avec le contrôle de version (*.tres). Lors de l'exportation d'un jeu, Godot sérialise les fichiers ressource sous forme de fichiers binaires (*.res) pour une vitesse et une compression accrues.

  • L'inspecteur de Godot Engine rend et édite les fichiers Resource immédiatement. En tant que tels, les utilisateurs n'ont souvent pas besoin de mettre en œuvre une logique personnalisée pour visualiser ou éditer leurs données. Pour ce faire, double-cliquez sur le fichier resource dans le dock Système de Fichiers ou cliquez sur l'icône de dossier dans l'inspecteur et ouvrez le fichier dans la boîte de dialogue.

  • Elles peuvent étendre d'autres types de ressource, outre la Resource de base.

Godot facilite la création de Resources personnalisées dans l'inspecteur.

  1. Créez un objet Ressource dans l'Inspecteur. Cela peut même être un type qui dérive de Ressource, du moment que votre script hérite de ce type.

  2. Définissez la propriété script dans l'inspecteur comme étant votre script.

L'inspecteur affiche désormais les propriétés personnalisées de votre script de ressources. Si on modifie ces valeurs et enregistre la ressource, l'inspecteur sérialise également les propriétés personnalisées ! Pour enregistrer une ressource de l'inspecteur, cliquez sur le menu Outils de l'inspecteur (en haut à droite), puis sélectionnez "Enregistrer" ou "Enregistrer sous ...".

Si le langage du script prend en charge les classes de script, cela simplifie le processus. Définir un nom pour votre script l'ajoutera à la boîte de dialogue de création de l'inspecteur. Cela ajoutera automatiquement votre script à l'objet Ressource que vous créez.

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.

Note

Les scripts de Resource sont similaires à ScriptableObjects de Unity. L'Inspecteur fournit un support intégré pour les ressources personnalisées. Si nécessaire, les utilisateurs peuvent même concevoir leurs propres scripts d’outils basés sur Control, et les combiner avec un EditorPlugin pour créer des visualisations et des éditeurs personnalisés pour leurs données.

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.

Les CurveTables sont la même chose, sauf qu'elles sont mappées à un tableau de valeurs flottantes ou à un objet ressource Curve/Curve2D.

Avertissement

Attention, les fichiers de ressources (*.tres/*.res) vont stocker le chemin du script qu'ils utilisent dans le fichier. Une fois chargés, ils vont chercher et charger ce script comme une extension de leur type. Cela signifie que tenter d’affecter une sous-classe, c’est-à-dire une classe interne à un script (comme l’utilisation du mot clé class dans GDScript) ne fonctionnera pas. Godot ne sérialisera pas correctement les propriétés personnalisées sur la sous-classe de script.

Dans l'exemple ci-dessous, Godot chargerait le script Nœud, verrait qu'il n'étend pas Ressource, puis déterminerait que le script n'a pas pu être chargé pour l'objet Ressource car les types sont 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")