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.

Tout ce que Godot sauvegarde ou charge depuis le disque est une ressource. Que ce soit une scène(un fichier .tscn ou .scn), une image, un script... Quelques exemples de Resource : Texture, Script, Mesh, Animation, AudioStream, Font, Translation.

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

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.

Pour être plus spécifique, voici une Texture dans un nœud Sprite :

../../_images/spriteprop.png

Cliquer sur l'aperçu de la ressources vous permet de voir et de configurer ses propriétés.

../../_images/resourcerobi.png

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():
        var res = load("res://robi.png") # Godot loads the Resource when it reads the line.
        get_node("sprite").texture = res

Vous pouvez également preload (précharger) des ressources. Contrairement à load (charger), cette fonction lira le fichier à partir du disque et le chargera au moment de la compilation. Par conséquent, vous ne pouvez pas appeler le préchargement avec un chemin variable : vous devez utiliser une chaîne constante.

func _ready():
        var res = preload("res://robi.png") # Godot loads the resource at compile-time
        get_node("sprite").texture = res

Chargement de scènes

Les scènes sont également des ressources, mais il y a une différence. Les scènes sauvegardées sur le disque dur sont des ressources de type PackedScene. Cela signifie que la scène est emballée à l'intérieur d'une ressource.

Pour obtenir une instance de la scène, la méthode PackedScene.instance() doit être utilisée.

func _on_shoot():
        var bullet = preload("res://bullet.tscn").instance()
        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.

Cette approche présente plusieurs avantages. Comme la fonction PackedScene.instance() est rapide, vous pouvez créez de nouveaux ennemis, balles, effets, etc... sans avoir à les recharger à chaque fois à partir du disque dur. Il est important de se rappeler que, comme toujours, les images, les maillages, etc sont tous partagés entre les instances de la scène.

Libérer des ressources

Lorsqu'une Resource n'est plus utilisée, elle se libère automatiquement. Puisque, dans la plupart des cas, les ressources sont contenues dans des Nœuds, quand un nœud est libéré, le moteur libère également toutes les ressources de ce nœud si aucun autres nœuds ne les utilisent.

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.

Cela présente de nombreux avantages distincts par rapport aux structures de données alternatives telles que les fichiers JSON, CSV ou TXT personnalisés. Les utilisateurs peuvent uniquement importer ces assets en tant que Dictionnaire (JSON) ou en tant que Fichier à analyser. Ce qui distingue les Resources, c’est leur héritage de Objet, Référence, et Resource :

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

Quelques exemples.

# bot_stats.gd
extends Resource
export(int) var health
export(Resource) var sub_resource
export(Array, String) var strings

# 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

# bot.gd
extends KinematicBody

export(Resource) var stats

func _ready():
    # Uses an implicit, duck-typed interface for any 'health'-compatible resources.
    if stats:
        print(stats.health) # Prints '10'.

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.

Les DataTables et CurveTables de Unreal Engine 4 sont également faciles à recréer à l'aide de scripts de Resources. Les DataTables sont une chaîne mappée à une structure personnalisée, similaire à un dictionnaire mappant une chaîne à un script de ressource personnalisé secondaire.

# 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)

Au lieu de simplement aligner les valeurs du dictionnaire, on pourrait aussi, alternativement ...

  1. Importer une table de valeurs à partir d'une feuille de calcul et générer ces paires clé-valeur, ou ...

  2. Concevez une visualisation dans l'éditeur et créez un plug-in simple qui l'ajoutera à l'inspecteur lorsque vous ouvrirez ces types de ressources.

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("res://my_res.tres", my_res)