Загрузка ресурсов — preload, load, threaded
Как Godot загружает ассеты — синхронно, асинхронно, с прогрессом.
В Godot нет отдельной системы вроде Unity Addressables — встроенный механизм покрывает большинство сценариев через несколько API.
Три способа загрузки
1. preload — статичная, на этапе парсинга
const ENEMY_SCENE := preload("res://scenes/enemy.tscn")
const FIRE_SOUND := preload("res://audio/fire.ogg")
func spawn() -> void:
var enemy = ENEMY_SCENE.instantiate()
add_child(enemy)
preload — это директива компилятора GDScript. Ресурс загружается, когда сам скрипт
загружается (один раз, кешируется). Самый быстрый способ при инстанцировании.
Плюс: ноль пауз в рантайме. Минус: ассет всегда в памяти, пока скрипт жив. Не подходит для тяжёлой геометрии, которая нужна не всегда.
2. load — динамическая, синхронная
func load_level(name: String) -> void:
var path = "res://levels/%s.tscn" % name
var scene = load(path) as PackedScene
if scene == null:
push_error("Failed to load %s" % path)
return
get_tree().change_scene_to_packed(scene)
load блокирует поток, пока не загрузит. Подходит для лёгких ресурсов в моменты, где пауза не
заметна.
3. ResourceLoader.load_threaded_request — асинхронная
Для тяжёлых сцен/моделей:
var loading_path: String
func start_load(scene_path: String) -> void:
loading_path = scene_path
ResourceLoader.load_threaded_request(scene_path)
func _process(_delta: float) -> void:
if loading_path.is_empty():
return
var progress := []
var status = ResourceLoader.load_threaded_get_status(loading_path, progress)
match status:
ResourceLoader.THREAD_LOAD_IN_PROGRESS:
$LoadingBar.value = progress[0] * 100.0 # 0..1
ResourceLoader.THREAD_LOAD_LOADED:
var resource = ResourceLoader.load_threaded_get(loading_path)
_on_loaded(resource)
loading_path = ""
ResourceLoader.THREAD_LOAD_FAILED:
push_error("Load failed: ", loading_path)
loading_path = ""
func _on_loaded(scene: PackedScene) -> void:
get_tree().change_scene_to_packed(scene)
progress — array, где progress[0] это float 0..1 прогресса. Можно строить настоящий
loading screen.
Это аналог Unity Addressables LoadAssetAsync: пока игрок проходит уровень, в фоне грузим
следующий. По достижении 100% — мгновенный переход.
Подсказка типа
load и load_threaded_get возвращают Resource. Чтобы получить типизированный объект,
используйте as:
var scene := load(path) as PackedScene
var texture := load(tex_path) as Texture2D
var data := load(cfg_path) as WeaponData
Если cast не удался — будет null.
PCK-пакеты
Godot позволяет упаковывать ассеты в PCK-файлы (.pck — Pack file) и загружать в рантайме.
Используется для DLC, hot updates, mod-поддержки:
# Загрузить PCK в текущий проект
if not ProjectSettings.load_resource_pack("res://dlc/level_pack_2.pck"):
push_error("Failed to load DLC pack")
else:
# Теперь доступны ассеты из pack по их путям
var dlc_scene = load("res://dlc_levels/extra_01.tscn")
PCK создаётся через Project → Export в режиме “Export PCK/Zip” (без бинарника движка).
Code splitting: import('./heavy-module') асинхронно — браузер грузит chunk по сети.
load_threaded_request — то же концептуально, но для ассетов.
Unity Addressables ↔ Godot PCK + ResourceLoader. У Godot нет такой удобной remote-CDN интеграции из коробки, но базовые механизмы есть.
Кеширование
load дважды по одному пути вернёт тот же Resource (рефкаунтная природа Resource):
var a = load("res://item.tres")
var b = load("res://item.tres")
print(a == b) # true — это один и тот же объект
Если хотите независимую копию (например, чтобы менять без побочных эффектов):
var clone = a.duplicate()
Для глубокого клона — duplicate(true) (рекурсивно дублирует вложенные ресурсы).
resource_local_to_scene
Свойство Resource, которое заставляет каждую сцену клонировать ресурс при загрузке. Полезно для материалов, которые должны быть уникальны на каждом инстансе:
var mat = StandardMaterial3D.new()
mat.resource_local_to_scene = true
# Теперь при инстансах сцены каждый получит свою копию
Освобождение памяти
Resource удаляется автоматически по reference count. Если у вас Singleton-ссылки или global arrays хранят ассеты, явно занулите их:
my_cache.clear() # массив со ссылками
preloaded_scene = null
После последней ссылки на следующий кадр Godot почистит память.
Что делать, когда что-то “не выгружается”
- Используйте Resource Monitor в Debugger → Monitor → Objects: показывает живые объекты в памяти. Если число только растёт — утечка.
- Remote Scene Tree — позволяет инспектировать запущенную сцену из редактора. Если узел “должен был быть удалён, но висит” — увидите.
queue_free()вместоfree()— освобождение в конце кадра, безопаснее для текущих сигналов.
В следующей главе — сборка и оптимизация.