Как стать автором
Обновить

Сохранение в файл в Unity3D

Начну с того, что в Unity есть своя система сохранений PlayerPrefs, но она имеет ряд минусов:

1) Не всем хочется засорять реестр.
2) Нет возможности сделать несколько слотов сохранения (костыли с припиской не считаются).
3) Нет возможности передать сохранение или перенести на другое устройство.

Поэтому я решил сделать свою систему сохранений.

image

В своих целях я писал на местной интерпретации Javascript, но, думаю, можно перенести и на C#.

Создание и импорт файла


Для начала получаем ссылку на текущий файл. Для примера возьмем локальную папку name_data/StreamingAssets/Saves. Можно выставить любой путь.

Название файла задаем в переменной saveName, плюс к нему будет приписываться порядковый номер сохранения.

playerDataPath = Application.streamingAssetsPath +'/Saves/'+ saveName + PlayerPrefs.GetInt(«CurrentSave») + ".db";


Если слоты сохранения не нужны, можно убрать PlayerPrefs.GetInt(«CurrentSave»).
Назначать номер слота — PlayerPrefs.SetInt(«CurrentSave», num), где num — порядковый номер.
".db" — формат файла. На самом деле, это обычный текстовый документ, но лучше придумать свой формат, чтобы не искушать пользователя отредактировать.

Итак, мы имеем ссылку на файл в переменной playerDataPath. Далее проверяем нахождения файла по ссылке, и если его там нет — создаем.
if (!File.Exists(playerDataPath)){
var dataWriter: StreamWriter = new StreamWriter(playerDataPath);
}

Если он там есть — считываем в массив Saves.
else {
var dataReader = new File.OpenText(playerDataPath);
for(var i: int = 1; i < Saves.length; i++)
{
Saves[i] = dataReader.ReadLine();
}
}

И да, в массиве стоит сразу указать количество строк, которое нам потребуется, так как такой тип массивов не динамический.

Сохранение.


Создадим функцию Save для сохранения. При вызове построчно записываем массив в наш текстовый файл.
function Save(){
var dataWriter: StreamWriter = new StreamWriter(playerDataPath);
for(var i: int = 1; i < Saves.length; i++)
{
dataWriter.WriteLine(Saves[i]);
}
saved = true;
dataWriter.Flush();
dataWriter.Close();
}

Основная часть готова.

Получение и запись данных


В чем плюс этого способа — не имеет значения, в каком формате мы сохраняем данные — в float, int или String — все равно все хранится в виде текста.
При получении просто преобразовываем в нужный формат. Для удобства сделаем названия функций такими же, как и в PlayerPrefs.
Например, нам нужен int. Вызываем функцию GetInt с номером нужной нам строчки.
function GetInt (i: int): int {
if (Saves[i] != ""){
return int.Parse(Saves[i]);
}
else {
return 0;
}
}

Для сохранения вызываем функцию SetInt, куда отправляем номер строчки и число для сохранения.
function SetInt (i: int, v: int){
Saves[i] = v.ToString();
saved = false;
}

Аналогично можно сделать и с другими типами переменных.
function SetFloat (i: int, v: float){
Saves[i] = v.ToString();
saved = false;
}

function GetFloat(i: int): float {
if (Saves[i] != ""){
return float.Parse(Saves[i]);
}
else {
return 0f;
}
}


Другие функции


Можно сделать удаление конкретного сохранения.
Для этого вызываем DeleteSaveFile с номером нужного файла. Если файл только один — номер будет равен нулю.
function DeleteSaveFile (i: int){
var tempPlayerDataPath = Application.streamingAssetsPath +'/Saves/'+ saveName + i + ".db";
if (File.Exists(tempPlayerDataPath)){
File.Delete(tempPlayerDataPath);
Debug.Log(«Delete File: » +tempPlayerDataPath);
}
else {
Debug.Log(«File not found»);
}
}

Или, например, можно очистить конкретный файл.
function ClearSaveFile (){
for(var i: int = 1; i < Saves.length; i++)
{
Saves[i] = "";
}
Debug.Log(«Clean Complite»);
Save();
}

Если нужно, чтобы сохранение происходило про выходе из игры или при загрузке другого уровня, пользуемся встроенной функцией OnDisable. Она вызывается автоматически.
function OnDisable(){
Save();
}


Вот здесь я сделал демонстрацию с кубиками:



Можно скачать уже готовый ассет для юнити, вместе с демкой из видео.
Подробное FAQ по уже готовому скрипту.

Всем спасибо за внимание, буду очень рад критике.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.