Проблема
Вам необходимо сохранять и загружать локальные данные между игровыми сессиями.
Решение
Система ввода/вывода файлов в Godot основана на объекте FileAccess. Файл открывается с помощью вызова функции open().
var file = FileAccess.open("user://myfile.name", File.READ)
Предупреждение!!! Данные пользователя следует хранить только по пути user://. В то время как res:// можно использовать при запуске из редактора, при экспорте проекта путь res:// становится доступным только для чтения.
Второй аргумент после пути файла — это «Флаг режима», который может быть одним из следующих:
- FileAccess.READ — Открыть для чтения.
- FileAccess.WRITE — Открыть для записи. Создает файл, если он не существует, и обрезает, если существует.
- FileAccess.READ_WRITE — Открыть для чтения и записи. Не обрезает файл.
- FileAccess.WRITE_READ — Открыть для чтения/записи. Создает файл, если он не существует, и обрезает, если существует.
Хранение данных
Вы можете сохранять данные, используя их конкретный тип данных (например, store_float(), store_string() и так далее) или использовать общую функцию store_var(), которая будет использовать встроенную в Godot сериализацию для кодирования ваших данных, включая сложные данные, такие как объекты (об этом позже).
Давайте начнем с небольшого примера: сохранения рекорда игрока. Мы можем написать функцию, которую можно вызвать всякий раз, когда необходимо сохранить счет:
var save_path = "user://score.save"
func save_score():
var file = FileAccess.open(save_path, FileAccess.WRITE)
file.store_var(highscore)
Мы сохраняем наш счет, но нам нужно иметь возможность загрузить его при запуске игры:
func load_score():
if FileAccess.file_exists(save_path):
print("file found")
var file = FileAccess.open(save_path, FileAccess.READ)
highscore = file.get_var()
else:
print("file not found")
highscore = 0
Не забудьте проверить существование файла перед попыткой чтения из него — он может отсутствовать! В таком случае вы можете использовать значение по умолчанию.
Функцию store_var() и get_var() можно использовать столько раз, сколько необходимо для любого количества значений.
Сохранение Ресурсов
Вышеописанный метод отлично работает, когда вам нужно сохранить всего лишь несколько значений. Для более сложных ситуаций вы можете сохранять свои данные в Ресурс, так же, как это делает Godot. Godot сохраняет все свои Ресурсы данных в файлах с расширением .tres (анимации, тайлсеты, шейдеры и так далее), и вы тоже можете!
Для сохранения и загрузки Ресурсов используйте классы ResourceSaver и ResourceLoader в Godot.
Для данного примера предположим, что у вас есть все данные о характеристиках вашего персонажа, сохраненные в Ресурсе, как показано ниже:
extends Resource
class_name PlayerData
var level = 1
var experience = 100
var strength = 5
var intelligence = 3
var charisma = 2
Затем вы можете сохранять и загружать данные следующим образом:
func load_character_data():
if ResourceLoader.exists(save_path):
return load(save_path)
return null
func save_character_data(data):
ResourceSaver.save(data, save_path)
Ресурсы могут содержать подресурсы, так что вы можете включить в них, например, ресурс инвентаря игрока, и так далее.
Что насчет JSON?
Я часто вижу этот вопрос (и некоторые читатели, возможно, уже задают его): «А что, если я хочу использовать JSON для сохранения моих данных?» Вот мой ответ:
Не используйте JSON для ваших файлов сохранения!
Хотя Godot поддерживает JSON, сохранение игровых данных — не его предназначение. JSON — это формат обмена данными, его цель — позволить системам, использующим разные форматы данных и/или языки, обмениваться данными между собой.
Это означает, что у JSON есть ограничения, которые являются недостатками для вас, когда речь идет о сохранении ваших игровых данных. JSON не поддерживает многие типы данных (например, нет разделения между int и float), поэтому вам придется много конвертировать и проверять данные при их сохранении/загрузке. Это неудобно и занимает много времени.
Не тратьте свое время зря. Используя встроенную сериализацию Godot, вы можете сохранять нативные объекты Godot — узлы (Nodes), ресурсы, даже сцены — без особых усилий, что означает меньше кода и меньше ошибок.
Это и есть причина, по которой сам Godot не использует JSON для сохранения сцен и ресурсов.
Эта статья только касается поверхности того, что можно сделать с FileAccess. Для полного списка доступных методов FileAccess обратитесь к документации FileAccess.