Загрузка и сохранение файла времени выполнения

См. также

Информацию о сохранении и загрузке игрового процесса см. в Сохранение игр.

Иногда экспорт пакетов, патчей и модов не идеален, если вы хотите, чтобы игроки могли загружать пользовательский контент в свой проект. Для этого пользователям необходимо создать PCK- или ZIP-файл в редакторе Godot, содержащий ресурсы, импортированные Godot.

Примеры вариантов использования загрузки и сохранения файлов во время выполнения включают в себя:

  • Загрузка пакетов текстур, разработанных для игры.

  • Загрузка пользовательских аудиодорожек и их воспроизведение на игровой радиостанции.

  • Загрузка пользовательских уровней или 3D-моделей, которые можно разработать с помощью любого 3D DCC, который может экспортировать в glTF или FBX (включая сцены glTF, сохраненные Godot во время выполнения).

  • Использование пользовательских шрифтов для меню и HUD.

  • Сохранение/загрузка формата файла, который может содержать несколько файлов, но при этом может быть легко прочитан другими приложениями (ZIP).

  • Загрузка файлов, созданных другой игрой или программой, или даже файлов игровых данных из другой игры, не созданной с помощью Godot.

Загрузку файла во время выполнения можно совмещать с HTTP-запросами для непосредственной загрузки ресурсов из Интернета.

Предупреждение

Не используйте этот подход к загрузке ресурсов, входящих в проект, так как он менее эффективен и не позволяет использовать возможности Godot по управлению ресурсами (например, переназначение трансляций). Подробности см. в Процесс импорта.

См. также

Вы можете увидеть, как сохранение и загрузка работают в действии, используя демонстрационный проект Сохранение и Загрузка файлов во время выполнения (сериализация)».

Простые текстовые и двоичные файлы

Класс Godot FileAccess предоставляет методы для доступа к файлам в файловой системе для чтения и записи:

func save_file(content):
    var file = FileAccess.open("/path/to/file.txt", FileAccess.WRITE)
    file.store_string(content)

func load_file():
    var file = FileAccess.open("/path/to/file.txt", FileAccess.READ)
    var content = file.get_as_text()
    return content

Для работы с пользовательскими двоичными форматами (например, для загрузки файлов, не поддерживаемых Godot), FileAccess предоставляет несколько методов для чтения/записи целых чисел, чисел с плавающей точкой, строк и т. д. Имена этих методов FileAccess начинаются с get_ и store_.

Если вам нужен больший контроль над чтением двоичных файлов или нужно читать двоичные потоки, не являющиеся частью файла, PackedByteArray предоставляет несколько вспомогательных методов для декодирования/кодирования последовательностей байтов в целые числа, числа с плавающей точкой, строки и другие типы. Имена этих методов PackedByteArray начинаются с decode_ и encode_. См. также API двоичной сериализации.

Images (Изображения)

Статический метод изображения Image.load_from_file обрабатывает все: от определения формата на основе расширения файла до чтения файла с диска.

Если вам нужна обработка ошибок или больший контроль (например, изменение масштаба загрузки SVG), используйте один из следующих методов в зависимости от формата файла:

Godot также может сохранять несколько форматов изображений во время выполнения, используя следующие методы:

Методы с суффиксом to_buffer сохраняют изображение в массиве PackedByteArray, а не в файловой системе. Это полезно для передачи изображения по сети или в ZIP-архиве без необходимости записи его в файловую систему. Это может повысить производительность за счёт снижения нагрузки на ввод-вывод.

Примечание

При отображении загруженного изображения на 3D-поверхности обязательно вызовите метод Image.generate_mipmaps, чтобы текстура не выглядела зернистой при просмотре на расстоянии. Это также полезно в 2D при выполнении инструкций по уменьшению алиасинга при понижении частоты дискретизации.

Пример загрузки изображения и отображения его в узле TextureRect (требующем преобразования в ImageTexture):

# Load an image of any format supported by Godot from the filesystem.
var image = Image.load_from_file(path)
# Optionally, generate mipmaps if displaying the texture on a 3D surface
# so that the texture doesn't look grainy when viewed at a distance.
#image.generate_mipmaps()
$TextureRect.texture = ImageTexture.create_from_image(image)

# Save the loaded Image to a PNG image.
image.save_png("/path/to/file.png")

# Save the converted ImageTexture to a PNG image.
$TextureRect.texture.get_image().save_png("/path/to/file.png")

Аудио/видео файлы

Godot поддерживает загрузку аудио в форматах Ogg Vorbis, MP3 и WAV во время работы. Обратите внимание, что не все файлы с расширением .ogg являются файлами Ogg Vorbis. Некоторые из них могут быть видео в формате Ogg Theora или содержать аудио Opus в контейнере Ogg. Такие файлы не будут корректно загружаться как аудиофайлы в Godot.

Пример загрузки аудиофайла Ogg Vorbis в узел AudioStreamPlayer:

$AudioStreamPlayer.stream = AudioStreamOggVorbis.load_from_file(path)

Пример загрузки видеофайла Ogg Theora в узел VideoStreamPlayer:

var video_stream_theora = VideoStreamTheora.new()
# File extension is ignored, so it is possible to load Ogg Theora videos
# that have a `.ogg` extension this way.
video_stream_theora.file = "/path/to/file.ogv"
$VideoStreamPlayer.stream = video_stream_theora

# VideoStreamPlayer's Autoplay property won't work if the stream is empty
# before this property is set, so call `play()` after setting `stream`.
$VideoStreamPlayer.play()

3D сцены

Godot обеспечивает первоклассную поддержку glTF 2.0 как в редакторе, так и в экспортированных проектах. Используя GLTFDocument и GLTFState вместе, Godot может загружать и сохранять файлы glTF в экспортированных проектах как в текстовом (.gltf), так и в двоичном (.glb) формате. Предпочтительнее двоичный формат, поскольку он быстрее пишется и компактнее, но текстовый формат проще отлаживать.

Since Godot 4.3, FBX scenes can also be loaded (but not saved) at runtime using the FBXDocument and FBXState classes. The code to do so is the same as glTF, but you will need to replace all instances of GLTFDocument and GLTFState with FBXDocument and FBXState in the code samples below.

Пример загрузки сцены glTF и добавления ее корневого узла к сцене:

# Load an existing glTF scene.
# GLTFState is used by GLTFDocument to store the loaded scene's state.
# GLTFDocument is the class that handles actually loading glTF data into a Godot node tree,
# which means it supports glTF features such as lights and cameras.
var gltf_document_load = GLTFDocument.new()
var gltf_state_load = GLTFState.new()
var error = gltf_document_load.append_from_file("/path/to/file.gltf", gltf_state_load)
if error == OK:
    var gltf_scene_root_node = gltf_document_load.generate_scene(gltf_state_load)
    add_child(gltf_scene_root_node)
else:
    show_error("Couldn't load glTF scene (error code: %s)." % error_string(error))

# Save a new glTF scene.
var gltf_document_save := GLTFDocument.new()
var gltf_state_save := GLTFState.new()
gltf_document_save.append_from_scene(gltf_scene_root_node, gltf_state_save)
# The file extension in the output `path` (`.gltf` or `.glb`) determines
# whether the output uses text or binary format.
# `GLTFDocument.generate_buffer()` is also available for saving to memory.
gltf_document_save.write_to_filesystem(gltf_state_save, path)

Примечание

При загрузке сцены glTF необходимо задать базовый путь для корректной загрузки внешних ресурсов, таких как текстуры. При загрузке из файла базовый путь автоматически указывает на папку, содержащую файл. При загрузке из буфера этот базовый путь необходимо задать вручную, так как Godot не может его определить.

Чтобы задать базовый путь, установите GLTFState.base_path на вашем экземпляре GLTFState перед вызовом GLTFDocument.append_from_buffer или GLTFDocument.append_from_file.

Fonts (Шрифты)

FontFile.load_dynamic_font поддерживает следующие форматы файлов шрифтов: TTF, OTF, WOFF, WOFF2, PFB, PFM

С другой стороны, FontFile.load_bitmap_font поддерживает формат BMFont (.fnt или .font).

Кроме того, можно загрузить любой шрифт, установленный в системе, используя поддержку Godot для Системные шрифты.

Пример автоматической загрузки файла шрифта в соответствии с его расширением и последующего добавления его в качестве переопределения темы к узлу Label:

var path = "/path/to/font.ttf"
var path_lower = path.to_lower()
var font_file = FontFile.new()
if (
        path_lower.ends_with(".ttf")
        or path_lower.ends_with(".otf")
        or path_lower.ends_with(".woff")
        or path_lower.ends_with(".woff2")
        or path_lower.ends_with(".pfb")
        or path_lower.ends_with(".pfm")
):
    font_file.load_dynamic_font(path)
elif path_lower.ends_with(".fnt") or path_lower.ends_with(".font"):
    font_file.load_bitmap_font(path)
else:
    push_error("Invalid font file format.")

if not font_file.data.is_empty():
    # If font was loaded successfully, add it as a theme override.
    $Label.add_theme_font_override("font", font_file)

ZIP-архивы

Godot поддерживает чтение и запись ZIP-архивов с помощью классов ZIPReader и ZIPPacker. Это позволяет использовать любые ZIP-файлы, включая файлы, созданные функцией Godot "Export PCK/ZIP" (хотя они будут содержать импортированные ресурсы Godot, а не исходные файлы проекта).

Примечание

Используйте ProjectSettings.load_resource_pack для загрузки PCK- или ZIP-файлов, экспортированных Godot как additional data packs. Этот подход предпочтителен для DLC, поскольку он обеспечивает бесперебойное взаимодействие с дополнительными пакетами данных (виртуальная файловая система).

Поддержку ZIP-архивов можно объединить с загрузкой изображений во время выполнения, 3D-сцен и аудио, чтобы обеспечить бесперебойный процесс моддинга без необходимости использования редактора Godot для создания файлов PCK/ZIP.

Пример, который перечисляет файлы в ZIP-архиве в узле ItemList, а затем записывает считанное из него содержимое в новый ZIP-архив (по сути дублируя архив):

# Load an existing ZIP archive.
var zip_reader = ZIPReader.new()
zip_reader.open(path)
var files = zip_reader.get_files()
# The list of files isn't sorted by default. Sort it for more consistent processing.
files.sort()
for file in files:
    $ItemList.add_item(file, null)
    # Make folders disabled in the list.
    $ItemList.set_item_disabled(-1, file.ends_with("/"))

# Save a new ZIP archive.
var zip_packer = ZIPPacker.new()
var error = zip_packer.open(path)
if error != OK:
    push_error("Couldn't open path for saving ZIP archive (error code: %s)." % error_string(error))
    return

# Reuse the above ZIPReader instance to read files from an existing ZIP archive.
for file in zip_reader.get_files():
    zip_packer.start_file(file)
    zip_packer.write_file(zip_reader.read_file(file))
    zip_packer.close_file()

zip_packer.close()