I have a number of components whose variables I would like to be able save and load in a build as presets, the new(ish) Presets system would be ace but it doesn’t work at runtime a build.
I’ve tried saving the whole component using :-
public class SaveLoad : MonoBehaviour
{
public static List<IBrushable> savedComponents = new List<IBrushable>();
public int noOfSavedComponents;
void OnEnable(){
}
//it's static so we can call it from anywhere
public void Save(IBrushable brushable)
{
SaveLoad.savedComponents.Add(brushable);
BinaryFormatter bf = new BinaryFormatter();
//Application.persistentDataPath is a string, so if you wanted you can put that into debug.log if you want to know where save games are located
FileStream file = File.Create(Application.persistentDataPath + "/savedGames.gd"); //you can call it anything you want
bf.Serialize(file, SaveLoad.savedComponents);
file.Close();
noOfSavedComponents = savedComponents.Count;
}
public void Load()
{
if (File.Exists(Application.persistentDataPath + "/savedGames.gd"))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/savedGames.gd", FileMode.Open);
SaveLoad.savedComponents = (List<IBrushable>)bf.Deserialize(file);
file.Close();
}
}
}
But my class (IBrushable) derives from MonoBehaviour so isn’t serializable.
I’ve seen a few options and am not sure which is best to pursue:-
1.Have a separate class that doesn’t derive from MonoBehaviour which just has a load of variables, these could be read by my IBrushables and saved/loaded using the above code.
2.Use ScriptableObjects for each preset? Can these be serialized, saved and loaded inside a build?
I don’t know what the “best” way is. I’ve used either hard coded into a script as in your #1, or in a flat file as in your #3, and both have worked just fine.
JSON is just a standardized text file format and is handy for loading or saving data, such as your class variables you want to load. You can get similar functionality using other text formats such as xml, csv, or even your own custom format, so I wouldn’t get hung up on the format itself but just that you want to save this data to some text file and retrieve it (there’s various pros/cons to each file format if you were to consider formats other than JSON). It is handy that Unity has built in support for class serialization/deserialization using JSON though, as opposed to you having to write your own serialization methods for most other file formats.
Have been trying to use a ScriptableObject then saving/loading the file to/from disk using JsonUtillity and File.ReadAllText, File.WriteAllText but the Unity Editor is hanging when I try to create the ScriptableObject in the Editor (RightClick–> Create–> PresetCrossContainer). It seems to be something up with the OnEnable function but I can’t figure what…
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
[CreateAssetMenu]
public class PresetCrossContainer : ScriptableObject {
public int currentIndex = 0;
public List<PresetCross> presetCrosses = new List<PresetCross>(1);
void OnEnable(){
if (System.IO.File.Exists(Application.persistentDataPath + "\\MyFile.json")){
string jsonData = File.ReadAllText(Application.persistentDataPath + "\\MyFile.json");
Debug.Log(jsonData);
PresetCrossContainer data = ScriptableObject.CreateInstance<PresetCrossContainer>();
JsonUtility.FromJsonOverwrite (jsonData, data);
presetCrosses = data.presetCrosses;
}
}
public PresetCross GetCurrentPreset(){
return presetCrosses[currentIndex];
}
public PresetCross LoadNextPreset(){
currentIndex += 1;
currentIndex = (int)Nfmod(currentIndex, presetCrosses.Count);
return presetCrosses[currentIndex];
}
public void SavePreset(PresetCross presetCross){
presetCrosses.Add(presetCross);
currentIndex += 1;
Save(this);
}
public void DeletePreset(){
if(presetCrosses.Count > 1){
presetCrosses.RemoveAt(currentIndex);
currentIndex = (int)Nfmod(currentIndex, presetCrosses.Count);
Save(this);
}
}
void Save(PresetCrossContainer data){
string jsonData = JsonUtility.ToJson(data);
Debug.Log(Application.persistentDataPath);
File.WriteAllText(Application.persistentDataPath + "\\MyFile.json", jsonData);
}
float Nfmod(float a, float b)
{
return a - b * Mathf.Floor(a / b);
}
}
[System.Serializable]
public class PresetCross{
public MyEnums.BlockName blockName;
public MyEnums.RandomiseColor randomiseColor;
public MyEnums.RandomiseAngle randomiseAngle;
public Vector2 width;
public Vector2 height;
public Vector2 depth;
public bool depthOffset;
public PresetCross Copy()
{
PresetCross copy = new PresetCross();
copy.blockName = this.blockName;
copy.randomiseColor = this.randomiseColor;
copy.randomiseAngle = this.randomiseAngle;
copy.width = this.width;
copy.height = this.height;
copy.depth = this.depth;
copy.depthOffset = this.depthOffset;
return copy;
}
}
As per #1 you create class, to store information you need. Following to that you got method which call and load / save information strictly from there. Optionally this can be static class, with static variables. Depending on application.
Then, as completely separate module, you can crate class with methods, which read / write i.e. JSON file, to and from that first class. Ensuring, JSON based class is not bounded to the any mono game objects. Then you just leave a public method (s), to save / load file.
Personally I would avoid any ScriptableObjects. Is ok for prototyping. But your design will become messy, as it grows.
I meant exactly what I said.
I have no idea, where your surprise come from?
In my projects and approach, I have see no advantage, or even need of using it.
Full stop.
That’s great, no doubts you’re doing fine without them. Though they’re not only “ok for prototyping”. It’s been greatly demonstrated what can be achieved by using SOs and how powerful they are. Of course you can use alternative ways.
Other people (including me) are using SOs as foundation of their game framework without our design become ‘messy’ and we actually would advise to use SOs both as data storage and/or building blocks which help decouple systems throughout an OOP project.
In other words: it’s your shortcoming and not the problem with the tool.
Kindly please do not’t extract part of citation, from full context
At end of the day, there will be as many opinions, as people.
One thing I should have written, instead of Will, May.
Where my opinion stays where it was.
But hey, lets not derail the topic.
If you think is important, you can write to me in PM