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...
Ресурси
Вузли та ресурси
В цьому уроці ми зосередилися на класі Node в Godot, оскільки саме його ви використовуєте для кодування поведінки, і більшість функцій движка покладаються саме на нього. Є ще один тип даних, який так само важливий: Resource.
Вузли надають вам функціональність: вони малюють спрайти, тривимірні моделі, імітують фізику, впорядковують інтерфейс користувача тощо. Ресурси - це контейнери даних. Вони нічого не роблять самостійно: натомість, вузли використовують дані, що містяться в ресурсах.
Все, що Годо зберігає або завантажує з диска, є ресурсом. Будь то сцена (файл .tscn або .scn), зображення, скрипт... Ось кілька прикладів Resource:
Текстура
Script
Translation
Коли двигун завантажує ресурс з диска, він завантажує його лише один раз. Якщо копія цього ресурсу вже є в пам'яті, при спробі знову завантажити ресурс, кожен раз буде повертатися та сама копія. Оскільки ресурси містять лише дані, не потрібно дублювати їх.
Кожен об'єкт, чи то Вузол, чи Ресурс, може експортувати властивості. Існує багато типів властивостей, таких як String, integer, Vector2 тощо, і будь-який з цих типів може стати ресурсом. Це означає, що і вузли, і ресурси можуть містити ресурси типу властивостей:
Зовнішні та вбудовані
Існує два способи зберігання ресурсів:
Зовнішнє, збережене на диску у вигляді окремих файлів.
Вбудований, збережений всередині
.tscn, або у.scn, файлу.
Щоб бути більш конкретним, ось Texture2D у вузлі Sprite2D:
Натиснувши кнопку попереднього перегляду ресурсу, ви зможете переглянути властивості ресурсу.
Властивість 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
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;
}
Ви також можете попередньо завантажити ресурси. На відміну від load, ця функція читатиме файл із диска та завантажуватиме його під час компіляції. Як результат, ви не можете викликати preload зі змінним шляхом: вам потрібно використовувати постійний рядок.
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.
Завантаження сцен
Сцени також є ресурсами, але тут є підступ. Сцени, збережені на диску, є ресурсами типу PackedScene. Сцена упакована всередину Resource.
Щоб отримати екземпляр сцени, вам потрібно використати метод 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);
}
Цей метод створює вузли в ієрархії сцени, налаштовує їх і повертає кореневий вузол сцени. Потім ви можете додати його в вигляді нащадка будь-якому іншому вузлу.
Підхід має кілька переваг. Оскільки функція PackedScene.instantiate() є швидкою, ви можете створювати нових ворогів, кулі, ефекти тощо, не завантажуючи їх щоразу з диска. Пам’ятайте, що, як завжди, зображення, сітки тощо є спільними для екземплярів сцени.
Звільнення ресурсів
Коли Ресурс більше не використовується, він автоматично звільниться. Оскільки в більшості випадків ресурси містяться у вузлах, коли ви звільняєте вузол, система також звільняє всі ресурси, якими володіє, якщо жоден інший вузол їх не використовує.
Створення власних ресурсів
Як і будь-який об’єкт у Godot, користувачі також можуть створювати сценарії ресурсів. Сценарії ресурсів успадковують можливість вільного перекладу між властивостями об’єкта та серіалізованим текстом або двійковими даними (*.tres, *.res). Вони також успадковують керування пам’яттю для підрахунку посилань від типу RefCounted.
Це має багато явних переваг перед альтернативними структурами даних, такими як файли JSON, CSV або спеціальні TXT. Користувачі можуть імпортувати ці ресурси лише як Dictionary (JSON) або як FileAccess для аналізу. Що відрізняє Resources від інших, так це їх успадкування функцій Object, RefCounted і Resource:
Вони можуть визначати константи, тому константи з інших полів даних, або об'єктів, не потрібні.
Вони можуть визначати методи, включаючи методи встановлення/отримання (setter/getter) для властивостей. Це дозволяє абстрагувати та інкапсулювати основні дані. Якщо структура скрипту Resource потребує змін, то гра, що використовує Resource, не потребує їх.
Вони можуть визначати сигнали, тому Ресурси можуть реагувати на зміни в даних, якими вони керують.
Вони мають визначені властивості, тому користувачі впевнені на 100%, що їх дані будуть існувати.
Автосеріалізація та десеріалізація ресурсів є вбудованою функцією Godot Engine. Користувачам не потрібно застосовувати власну логіку для імпорту/експорту даних файлу ресурсу.
Ресурси можуть навіть використовувати вкладені ресурси рекурсивно, тобто користувачі можуть створювати ще складніші структури даних.
Користувачі можуть зберігати Ресурси як текстові файли (*.tres). Після експорту гри Godot серіалізує файли ресурсів у вигляді бінарних файлів (*.res) для збільшення швидкості та стиснення.
Інспектор Godot Engine рендерить та редагує файли ресурсів одразу після встановлення. Таким чином, користувачам часто не потрібно впроваджувати власну логіку для візуалізації або редагування своїх даних. Для цього двічі клацніть файл ресурсу на панелі файлової системи або клацніть значок папки в Інспекторі та відкрийте файл у діалоговому вікні.
Вони можуть розширювати інші типи ресурсів, окрім базового ресурсу.
Godot дозволяє легко створювати власні ресурси в Інспекторі.
Створіть новий об'єкт Resource в Інспекторі. Це може бути навіть тип, що є похідним від Resource, якщо ваш скрипт розширює цей тип.
Встановіть властивість
scriptв Інспекторі для вашого скрипту.
Інспектор тепер відображатиме користувацькі властивості вашого скрипта ресурсу. Якщо ви відредагуєте ці значення та збережете ресурс, Інспектор також серіалізує користувацькі властивості! Щоб зберегти ресурс з Інспектора, натисніть значок збереження у верхній частині Інспектора та виберіть «Зберегти» або «Зберегти як...».
Якщо мова скрипта підтримує script classes, це спрощує процес. Визначення назви лише для вашого скрипта додасть його до діалогового вікна створення інспектора. Це автоматично додасть ваш скрипт до об’єкта Resource, який ви створюєте.
Давайте розглянемо кілька прикладів. Створіть Resource і назвіть його bot_stats. Він має з’явитися на вкладці вашого файлу з повною назвою bot_stats.tres. Без скрипт це марно, тому давайте додамо трохи даних і логіки! Додайте до нього скрипт під назвою bot_stats.gd (або просто створіть новий скрипт, а потім перетягніть його туди).
Примітка
Щоб новий клас ресурсу відображався в графічному інтерфейсі створення ресурсу, потрібно вказати назву класу для GDScript або використати атрибут [GlobalClass] у 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>();
}
}
}
Тепер створіть CharacterBody3D, назвіть його Bot і додайте до нього такий скрипт:
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'.
}
}
}
}
Тепер виберіть вузол CharacterBody3D, який ми назвали bot, і перетягніть ресурс bot_stats.tres в інспектор. Має надрукувати 10! Очевидно, що це налаштування можна використовувати для більш розширених функцій, ніж це, але якщо ви дійсно розумієте, як це все працювало, вам слід зрозуміти все інше, пов’язане з ресурсами.
Примітка
Скрипти ресурсів схожі на ScriptableObjects в Unity. Інспектор забезпечує вбудовану підтримку користувацьких ресурсів. За бажанням користувачі можуть навіть розробити власні скрипти інструментів на основі контролю (Control) та комбінувати їх з EditorPlugin, щоб створити власні візуалізації та редактори для своїх даних.
DataTables і CurveTables Unreal Engine також легко відтворити за допомогою сценаріїв Resource. DataTables — це рядок, зіставлений зі спеціальною структурою, подібно до того, як словник зіставляє рядок із вторинним настроюваним сценарієм ресурсу.
# 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);
}
}
Замість того, щоб просто вписати значення Словника, можна також альтернативно:
Імпортувати таблицю значень із електронної таблиці та згенерувати пари ключ-значення або.
Розробіть візуалізацію в редакторі та створіть плагін, який додає її до інспектора, коли ви відкриваєте ці типи ресурсів.
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")
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");
}
}