Up to date

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

Ресурси

Вузли та ресурси

В цьому уроці ми зосередилися на класі Node в Godot, оскільки саме його ви використовуєте для кодування поведінки, і більшість функцій движка покладаються саме на нього. Є ще один тип даних, який так само важливий: Resource.

Вузли надають вам функціональність: вони малюють спрайти, тривимірні моделі, імітують фізику, впорядковують інтерфейс користувача тощо. Ресурси - це контейнери даних. Вони нічого не роблять самостійно: натомість, вузли використовують дані, що містяться в ресурсах.

Все, що Godot зберігає або завантажує з диска, є ресурсом. Будь то сцена (файл .tscn або .scn), зображення, скрипт... Ось кілька прикладів Resource:

Коли двигун завантажує ресурс з диска, він завантажує його лише один раз. Якщо копія цього ресурсу вже є в пам'яті, при спробі знову завантажити ресурс, кожен раз буде повертатися та сама копія. Оскільки ресурси містять лише дані, не потрібно дублювати їх.

Кожен об'єкт, чи то Вузол, чи Ресурс, може експортувати властивості. Існує багато типів властивостей, таких як String, integer, Vector2 тощо, і будь-який з цих типів може стати ресурсом. Це означає, що і вузли, і ресурси можуть містити ресурси типу властивостей:

../../_images/nodes_resources.webp

Зовнішні та вбудовані

Існує два способи зберігання ресурсів:

  1. Зовнішнє, збережене на диску у вигляді окремих файлів.

  2. Вбудований, збережений всередині .tscn, або у .scn, файлу.

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

Властивість Path (шлях) повідомляє нам, звідки береться ресурс. У цьому випадку воно походить від зображення PNG robi.png. Коли ресурс походить з такого файлу, це зовнішній ресурс. Якщо стерти шлях, або цей шлях порожній, він стане вбудованим ресурсом.

Перемикання між вбудованими та зовнішніми ресурсами відбувається під час збереження сцени. У наведеному вище прикладі, якщо стерти шлях "res://robi.png" і зберегти сцену, Godot збереже зображення всередині файла сцени .tscn.

Примітка

Навіть якщо ви зберігаєте вбудований ресурс, коли ви копіюєте сцену кілька разів, движок завантажить лише одну його копію.

Завантаження ресурсів з коду

Існує два способи завантаження ресурсів з коду. По-перше, ви в будь-який час можете використовувати функцію load():

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

Завантаження сцен

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)

Цей метод створює вузли в ієрархії сцени, налаштовує їх і повертає кореневий вузол сцени. Потім ви можете додати його в вигляді нащадка будь-якому іншому вузлу.

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.

Звільнення ресурсів

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.

Створення власних ресурсів

Як і будь-який об'єкт у Godot, користувачі також можуть скриптувати ресурси. Скрипти ресурсів успадковують можливість вільного переходу між властивостями об'єкта та серіалізованим текстом, чи двійковими (бінарними) даними (*.tres, *.res). Вони також успадковують управління пам'яттю підрахунком посилань типу Reference.

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:

  • Вони можуть визначати константи, тому константи з інших полів даних, або об'єктів, не потрібні.

  • Вони можуть визначати методи, включаючи методи встановлення/отримання (setter/getter) для властивостей. Це дозволяє абстрагувати та інкапсулювати основні дані. Якщо структура скрипту Resource потребує змін, то гра, що використовує Resource, не потребує їх.

  • Вони можуть визначати сигнали, тому Ресурси можуть реагувати на зміни в даних, якими вони керують.

  • Вони мають визначені властивості, тому користувачі впевнені на 100%, що їх дані будуть існувати.

  • Автосеріалізація та десеріалізація ресурсів є вбудованою функцією Godot Engine. Користувачам не потрібно застосовувати власну логіку для імпорту/експорту даних файлу ресурсу.

  • Ресурси можуть навіть використовувати вкладені ресурси рекурсивно, тобто користувачі можуть створювати ще складніші структури даних.

  • Користувачі можуть зберігати Ресурси як текстові файли (*.tres). Після експорту гри Godot серіалізує файли ресурсів у вигляді бінарних файлів (*.res) для збільшення швидкості та стиснення.

  • Інспектор Godot Engine виводить і редагує файли ресурсів з коробки. Таким чином, користувачам часто не потрібно застосовувати власну логіку для візуалізації, чи редагування, своїх даних. Для цього двічі клацніть файл ресурсу на панелі Файлова система, або натисніть значок папки в інспекторі та відкрийте файл у діалоговому вікні.

  • Вони можуть розширювати інші типи ресурсів, окрім базового ресурсу.

Godot дозволяє легко створювати власні ресурси в Інспекторі.

  1. Створіть звичайний об'єкт Resource в інспекторі. Це навіть може бути тип, який походить від ресурса, якщо ваш скрипт розширює цей тип.

  2. Встановіть властивість script в Інспекторі для вашого скрипту.

Інспектор тепер покаже ваші власні властивості скрипту Resource. Якщо редагувати ці значення і економити ресурс, Інспектор також серіалізує власні властивості! Щоб зберегти ресурс у Інспекторі, натисніть меню інструментів Інспектора (вгорі праворуч) та виберіть "Зберегти", або "Зберегти як ...".

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.

Примітка

Скрипти ресурсів схожі на ScriptableObjects в Unity. Інспектор забезпечує вбудовану підтримку користувацьких ресурсів. За бажанням користувачі можуть навіть розробити власні скрипти інструментів на основі контролю (Control) та комбінувати їх з EditorPlugin, щоб створити власні візуалізації та редактори для своїх даних.

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)

Замість того, щоб просто вписати значення Словника, можна також альтернативно:

  1. Імпортувати таблицю значень із електронної таблиці та згенерувати пари ключ-значення або.

  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 - це те саме, за винятком відображення масиву з десяткових значень, або об'єкта ресурсу Curve/Curve2D .

Попередження

Пильнуйте, щоб файли ресурсів (*.tres /*.res) зберігали у файлі шлях до скрипту, який вони використовують. При завантаженні вони будуть отримувати та завантажувати цей скрипт, як розширення свого типу. Це означає, що спроба призначити підклас, тобто внутрішній клас скрипту (наприклад, з допомогою ключового слова class в GDScript), не буде працювати. Godot не буде належним чином серіалізувати власні властивості підкласу скрипту.

У наведеному нижче прикладі Godot завантажує скрипт Node, бачить, що він не розширюється Resource, а потім визначає, що скрипт не вдалося завантажити для об'єкта ресурсу, оскільки типи несумісні.

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