Раздельное сохранение данных

Программирование на Юнити.

Раздельное сохранение данных

Сообщение Sandirk 15 апр 2020, 17:13

Здравствуйте.

Реализовал в своей игре меню настроек и сохранение данных этих самых настроек. Код для скрипта сохранения делался основываясь на туториал от Brackeys.

Туториал:


Скрипты работают как нужно, ошибок не возникает. Сохранение данных на диск производится с помощью данной команды:
Синтаксис:
Используется csharp
public void SaveDat()
{
        SaveSystem.SaveData(this);
}
 


Её я вызываю каждый кадр. (Не знаю, насколько правильно перезаписывать данные ~60 раз в секунду, если возникнут проблемы изменю сценарий). Но речь не об этом.

Насколько я понял SaveSystem.SaveData(this); сохраняет абсолютно все внесённые настройки, указанные в скрипте "SaveData" (Я прикрепил его ниже). Однако помимо настроек, перезаписывающихся несколько раз в секунду автоматически возникла необходимость перезаписывать некоторые настройки только в тот момент, когда нажимается кнопка. Иначе говоря мне нужно записывать не все настройки одновременно, а лишь их часть, в то время как сохранение остальных настроек будет вызываться отдельно.

"SaveData" скрипт:
Синтаксис:
Используется csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class SaveData
{
    public int Mode;

    public float SuperRateRoll;
    public float RCRateRoll;

    public float SuperRatePitch;
    public float RCRatePitch;

    public float SuperRateYaw;
    public float RCRateYaw;

    public float SuperRateThrottle;
    public float RCRateThrottle;

    public SaveData(RatesLoader Rates)
    {
        Mode = Rates.Mode;

        SuperRateRoll = Rates.SuperRateRoll;
        RCRateRoll = Rates.RCRateRoll;

        SuperRatePitch = Rates.SuperRatePitch;
        RCRatePitch = Rates.RCRatePitch;

        SuperRateYaw = Rates.SuperRateYaw;
        RCRateYaw = Rates.RCRateYaw;

        SuperRateThrottle = Rates.SuperRateThrottle;
        RCRateThrottle = Rates.RCRateThrottle;
    }
}


"SaveSystem" скрипт:
Синтаксис:
Используется csharp
using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public static class SaveSystem
{
    public static void SaveData(RatesLoader Rates)
    {
        BinaryFormatter formatter = new BinaryFormatter();
        string path = Application.persistentDataPath + "/player.fun";
        FileStream stream = new FileStream(path, FileMode.Create);

        SaveData data = new SaveData(Rates);

        formatter.Serialize(stream, data);
        stream.Close();
    }

    public static SaveData LoadPlayer()
    {
        string path = Application.persistentDataPath + "/player.fun";
        if (File.Exists(path))
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(path, FileMode.Open);

            SaveData data = formatter.Deserialize(stream) as SaveData;
            stream.Close();

            return data;
        }
        else
        {
            Debug.LogError("Save file not found in" + path);
            return null;
        }
    }
}


Знаю, вопрос довольно объёмный, буду очень благодарен, если кто-то подскажет, как обстоять с моей проблемой.

Заранее спасибо.
Аватара пользователя
Sandirk
UNITрон
 
Сообщения: 150
Зарегистрирован: 04 фев 2019, 21:48

Re: Раздельное сохранение данных

Сообщение 1max1 15 апр 2020, 17:18

Тебе нужен еще один класс типа SaveData_2, засейвить часть SaveData не выйдет, только всё сразу. Либо делать сейвы не через сериализацию бинаркой, а как-то хитрожопо, возможно с рефлексией, но это неоправданно, лучше первый вариант.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Раздельное сохранение данных

Сообщение Sandirk 15 апр 2020, 17:23

1max1 писал(а):Тебе нужен еще один класс типа SaveData_2, засейвить часть SaveData не выйдет, только всё сразу. Либо делать сейвы не через сериализацию бинаркой, а как-то хитрожопо, возможно с рефлексией, но это неоправданно, лучше первый вариант.


Я тоже об этом думал, написал помимо нового SaveData_2 даже новый SaveSystem_2. Однако когда пытался загружать настройки получал ошибку object reference not set to an instance of an object. Попробую ещё раз (уже в четвёртый или пятый) если не выйдет пришлю сюда результат.

Однако спасибо за наводку, хоть знаю, что копаю в нужном направлении
Аватара пользователя
Sandirk
UNITрон
 
Сообщения: 150
Зарегистрирован: 04 фев 2019, 21:48

Re: Раздельное сохранение данных

Сообщение Sandirk 15 апр 2020, 17:48

1max1 писал(а):Тебе нужен еще один класс типа SaveData_2, засейвить часть SaveData не выйдет, только всё сразу. Либо делать сейвы не через сериализацию бинаркой, а как-то хитрожопо, возможно с рефлексией, но это неоправданно, лучше первый вариант.


После переделывания кода, как я и предполагал появилась ошибка "NullReferenceException: Object reference not set to an instance of an object
Drone_Preview.LoadNewData () (at Assets/Drone_Preview.cs:156)"
. Ошибка возникает каждый фрейм, когда я пытаюсь загрузить данные. Я прикрепил все переделанные коды ниже, отметил через два слеша строчку, в которой появляется ошибка. Уже не один день питаюсь понять, какую ссылку на объект я не указал. Может вы заметите, где я ошибся? Visual Studio ошибок не выдаёт весь код зелёный.

SaveData
Синтаксис:
Используется csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class SaveData
{
    public int Mode;

    public float SuperRateRoll;
    public float RCRateRoll;

    public float SuperRatePitch;
    public float RCRatePitch;

    public float SuperRateYaw;
    public float RCRateYaw;

    public float SuperRateThrottle;
    public float RCRateThrottle;

    public SaveData(RatesLoader Rates)
    {
        Mode = Rates.Mode;

        SuperRateRoll = Rates.SuperRateRoll;
        RCRateRoll = Rates.RCRateRoll;

        SuperRatePitch = Rates.SuperRatePitch;
        RCRatePitch = Rates.RCRatePitch;

        SuperRateYaw = Rates.SuperRateYaw;
        RCRateYaw = Rates.RCRateYaw;

        SuperRateThrottle = Rates.SuperRateThrottle;
        RCRateThrottle = Rates.RCRateThrottle;
    }
}
 


SaveNewData
Синтаксис:
Используется csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class SaveNewData
{
    public float RollCalibration;
    public float PitchCalibration;
    public float YawCalibration;
    public float ThrottleCalibration;

    public SaveNewData(RatesLoader NewRates)
    {
        RollCalibration = NewRates.RollCalibration;
        PitchCalibration = NewRates.PitchCalibration;
        YawCalibration = NewRates.YawCalibration;
        ThrottleCalibration = NewRates.ThrottleCalibration;
    }
}
 


SaveSystem
Синтаксис:
Используется csharp
using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System;

public static class SaveSystem
{
    public static void SaveData(RatesLoader Rates)
    {
        BinaryFormatter formatter = new BinaryFormatter();
        string path = Application.persistentDataPath + "/player.fun";
        FileStream stream = new FileStream(path, FileMode.Create);

        SaveData data = new SaveData(Rates);

        formatter.Serialize(stream, data);
        stream.Close();
    }

    public static void SaveNewData(RatesLoader Rates)
    {
        BinaryFormatter formatter = new BinaryFormatter();
        string path = Application.persistentDataPath + "/player.fun";
        FileStream stream = new FileStream(path, FileMode.Create);

        SaveNewData Newdata = new SaveNewData(Rates);

        formatter.Serialize(stream, Newdata);
        stream.Close();
    }

    public static SaveData LoadPlayer()
    {
        string path = Application.persistentDataPath + "/player.fun";
        if (File.Exists(path))
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(path, FileMode.Open);

            SaveData data = formatter.Deserialize(stream) as SaveData;
            stream.Close();

            return data;
        }
        else
        {
            Debug.LogError("Save file not found in" + path);
            return null;
        }
    }

    public static SaveNewData LoadNewPlayer()
    {
        string path = Application.persistentDataPath + "/player.fun";
        if (File.Exists(path))
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(path, FileMode.Open);

            SaveNewData Newdata = formatter.Deserialize(stream) as SaveNewData;
            stream.Close();

            return Newdata;
        }
        else
        {
            Debug.LogError("Save file not found in" + path);
            return null;
        }
    }
}


RatesLoader (Фрагмент)
Синтаксис:
Используется csharp
    public void SaveDat()

// Сохранения вызываются из этих 2х строк
    public void SaveDat()
    {
        SaveSystem.SaveData(this);
    }

    public void SaveNewDat()
    {
        SaveSystem.SaveNewData(this);
    }


Drone_Previev (Ошибка находится здесь) (Фрагмент)
Синтаксис:
Используется csharp
    public void LoadData()
    {
        SaveData data = SaveSystem.LoadPlayer();

        Mode = data.Mode;

        SuperRateRoll = data.SuperRateRoll;
        RCRateRoll = data.RCRateRoll;

        SuperRatePitch = data.SuperRatePitch;
        RCRatePitch = data.RCRatePitch;

        SuperRateYaw = data.SuperRateYaw;
        RCRateYaw = data.RCRateYaw;

        SuperRateThrottle = data.SuperRateThrottle;
        RCRateThrottle = data.RCRateThrottle;

    }

    public void LoadNewData()
    {
        SaveNewData Newdata = SaveSystem.LoadNewPlayer();

        RollCalibration = Newdata.RollCalibration; // ТА САМАЯ СТРОЧКА, НА КОТОРОЙ ПО МНЕНИЮ КОНСОЛИ НАХОДИТСЯ ОШИБКА
        PitchCalibration = Newdata.PitchCalibration;
        YawCalibration = Newdata.YawCalibration;
        ThrottleCalibration = Newdata.ThrottleCalibration;

    }


Это большой объём информации, если вы сможете найти ошибку, я просто вас буду боготворить
Аватара пользователя
Sandirk
UNITрон
 
Сообщения: 150
Зарегистрирован: 04 фев 2019, 21:48

Re: Раздельное сохранение данных

Сообщение 1max1 15 апр 2020, 18:08

Ты 2 разных сейва пишешь в один и тот же файл.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Раздельное сохранение данных

Сообщение Sandirk 15 апр 2020, 18:12

1max1 писал(а):Ты 2 разных сейва пишешь в один и тот же файл.


Было подозрение, однако как писать их в разные файлы? Назначить в SaveSystem другой путь или вроде того? Если можно чуть подробнее
Аватара пользователя
Sandirk
UNITрон
 
Сообщения: 150
Зарегистрирован: 04 фев 2019, 21:48

Re: Раздельное сохранение данных

Сообщение 1max1 15 апр 2020, 18:42

player.fun -> player_2.fun -> profit!
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Раздельное сохранение данных

Сообщение Sandirk 15 апр 2020, 19:32

1max1 писал(а):player.fun -> player_2.fun -> profit!


Я уж пробовал так, ошибка остаётся и к ней ещё новая добавляется:

Save file not found inC:/Users/Sandrik/AppData/LocalLow/DefaultCompany/QAV-R 220/player_1.fun
UnityEngine.Debug:LogError(Object)
SaveSystem:LoadNewPlayer() (at Assets/SaveSystem/SaveSystem.cs:67)
Drone_Preview:LoadNewData() (at Assets/Drone_Preview.cs:156)
Drone_Preview:FixedUpdate() (at Assets/Drone_Preview.cs:90)
Аватара пользователя
Sandirk
UNITрон
 
Сообщения: 150
Зарегистрирован: 04 фев 2019, 21:48

Re: Раздельное сохранение данных

Сообщение Sandirk 16 апр 2020, 00:44

Раз ответ так и не был найден, пришлось дойти до него самому. Оставлю здесь, мало-ли кому-нибудь пригодится.

Насколько я выяснил данные не сохранялись потому, что файл player.fun помещался прямо в папку игры.

Приписав в скрипте SaveSystem сценарий, создающий новую папку "saves" в папке игры и помещая файлы .fan в неё, проблемы удалось избежать. Теперь всё работает корректно.

Фрагмент из скрипта SaveSystem.
Синтаксис:
Используется csharp
public static void SaveNewData(RatesLoader NewRates)
    {
        if (!Directory.Exists(Application.persistentDataPath + "/saves"))
        {
            Directory.CreateDirectory(Application.persistentDataPath + "/saves");
        }

        BinaryFormatter formatterr = new BinaryFormatter();
        string patha = Application.persistentDataPath + "/saves/colibration.fun";
        FileStream streama = new FileStream(patha, FileMode.Create);
   
        SaveNewData Newdata = new SaveNewData(NewRates);
   
        formatterr.Serialize(streama, Newdata);
        streama.Close();
    }

    public static SaveData LoadPlayer()
    {
        string path = Application.persistentDataPath + "/saves/player.fun";
        if (File.Exists(path))
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(path, FileMode.Open);

            SaveData data = formatter.Deserialize(stream) as SaveData;
            stream.Close();

            return data;
        }
        else
        {
            Debug.LogError("Save file not found in " + path);
            return null;
        }
    }
Аватара пользователя
Sandirk
UNITрон
 
Сообщения: 150
Зарегистрирован: 04 фев 2019, 21:48


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 7