Please help me: How to save/load an increasing Integer ? In my Game the player has to search for 25 parts of a puzzle. If he has found and taken one the term “puzzlePartNumber = puzzlePartNumber + 1” must be saved. But how ? how? Please, a tip or an idea will give me a chance to continue !
Peter
Look into PlayerPrefs. You save key, value pair where the key is a string and the value is either floar, int, … and so on. You can load the value as well. It’s intended for use between sessions. Inside a session you can always just keep track of the variable yourself. So just save it OnApplicationQuit(), and load it somewhere on Awake().
Thank you for reply. With “public int puzzlePartNumber” and PlayerFrefs.SetInt(“Puzzle”, puzzlePartNumber) and PlayerPrefs.Save() it doesn’t work and there is no entry on the registy. Pity, but a good idea.
Peter
It does. You dont need to call Save() either, as it is automatically called OnApplicationQuit. You do however need to actually load the saved value once you launch your application again, so you are probably never doing something like puzzlePartNumber = PlayerPrefs.GetInt(“Puzzle”) at the start of your application, right?
As for yet, the saving doesn’t work, my problem. But the saving has to be implement not only OnApplicationQuit; it has to implement at runtime. For example: if (Physics.Raycast(ray, out hit,20) Inventory.Instance.PlaceItemToInventory(hit.collider.gameObject);
Now the player has taken the Puzzlepart in inventory and now the expression :
puzzlePartNumber = puzzlePartNumber + 1
has to be saved for the entire game (certainly this will be 25 parts at the end of the game). OnApplicationQuit is only necessary with pausing or quit for the next day. Various attemps with Json and BinaryFormatter have failed. Most difficult is saving of booleans (e.g. bool getPuzzle = false changed to bool getPuzzle = true).
Best regards Peter
But if the game is still running then the value is still saved in the variable? Or do you mean if you change the scene? then you have to use the PlayerPrefs and save before loading the new scene and then load the value in the new scene again. Or you make a script that is keeping all your important data, put it on a gameobject and use DontDestroyOnLoad to keep it in the next scene (Unity - Scripting API: Object.DontDestroyOnLoad)
Using PlayerPrefs, you would just need to set it everytime it increases, and load it when you change the scene. Inside the scene you then you the value you keep track off yourself (puzzlePartNumber).
However, i assumed that you wanted to save the variable between sessions, which is why i suggested PlayerPrefs in the first place. If you just want to save it between scenes at runtime, there are a few other options. The best ones are probably to make your SceneManager (or whatever object keeps track of this variable) a DontDestroyOnLoad, thus it persists between scenes. Or you make it a static variable, since it only exists once anyways (i assume?), thus being able to put and get it from anywhere. Both of these options would make the variable keep its value between scenes.
Thank you for those tips. In fact I want/have to save each changing of puzzlePartNumber or doorABCOpen= false/true at runtime (possible two/three times in one scene). The player has solved a quest and now he wants e.g. everytimes to walk through the door. Therefore the now existing doorABCOpen = true must be hold for the whole game. In my project these constellations frequently appear. The Save/Load - System is the hardest part of my project, but without, the player would be play without any disruption !?? No solution, of course.
Peter
I am not sure if I understand why you want to save that to that to disk during the game. Normally you set your variable dooABCOpen to true and then the variable “saves” that value? Changing scenes is another thing but Yoreki gave you a few hints for that.
Yes, of course. I think you missunderstood me. Once saved its saved all the game. But if in a scene were two or three puzzles the puzzlePartNumber will be saved two or three times in this scene.
Unfortunately most tutorials in the internet will not work (or I can’t get at it) or are to profound (e.g. Easy Save 3 in Asset Store).I will try free plugin : Component Save System by LowScope. Nevertheless many thanks for replying !
Peter
Why is it a problem if you need to save two or tree variables? Simply put them in an array instead? I agree that we seem to be talking past each other, thus I think you need to be a bit more specific what exactly your problem is, possibly with code example(s) you tried, what you expect it to do, what it does, possibly thrown exceptions, and so on.
This is probably mostly a language barrier, rather than an actual software problem.
You mentioned that the problem is when you have multiple variables that need to be saved. However, that should not be a problem. If you have multiple puzzlePartCount’s then you could put them in an array. While in the same scene, this array keeps track of your values. When closing the application or changing the scene, you save the values. When loading the application or a new scene, you load the values.
Thus no matter what you do, you would always have the correct value.
I’m just trying to understand what exactly is the problem in your situation.
I would say, try using the JSONUtility. It lets you convert between an object and a string. So you can create a class like SaveData, which contains your variables like which room the player is in, which items they have picked up, is DoorABC closed, then pass that object to JSONUtility.ToJSON() and receive a string in return. Then use System.IO.File.WriteAllText() to save the string to disk. Then the player can quit, and next time they play, use System.IO.File.ReadAllText() to get the string from the disk into your program, and then pass it to JSONUtility.FromJSON(). You it will give you back an instance of SaveData which you can now use like
if(saveData.PlayerHasGoblet){
//do stuff
}
There are many “better” ways to do saving, but my opinion is this is the right amount of complexity for where it sounds like you’re at.
here the code snippet:
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
public class SaveLoad : MonoBehaviour
{
public static void Save(T objectToSave, string saveName)
{
string path = Application.dataPath + “/SaveGames/”;
Directory.CreateDirectory(path);
BinaryFormatter bF = new BinaryFormatter();
FileStream fS = new FileStream(path + saveName + “.dat”, FileMode.Create);
try
{
bF.Serialize(fS, objectToSave);
Debug.Log(“saved” + objectToSave);
}
catch(SerializationException exception)
{
Debug.Log("Save failed. Error: " + exception.Message);
}
finally
{
fS.Close();
}
}
public static T Load(string saveName)
{
string path = Application.dataPath + “/SaveGames/”;
BinaryFormatter bF = new BinaryFormatter();
T returnValue = default;
try
{
FileStream fS = new FileStream(path + saveName + “.dat”, FileMode.Open);
returnValue = (T)bF.Deserialize(fS);
}
catch(SerializationException exception)
{
Debug.Log("Load faied. Error: " + exception.Message);
}
return returnValue;
}
and a part of the class TakeObject :
[System.Serializable]
public class TakeObject : MonoBehaviour
{
[HideInInspector]
public Aktionsmanager aktionsManager;
InteraktivesElement interaktivitaet;
public Room zimmer;
[HideInInspector]
public int puzzlePartNumber;
[HideInInspector]
public bool puzzle16Taken;
if (zimmer == Room.Diele)
{
aktionsManager.infoText.text = “No question, all have to be taken !”;
if (Physics.Raycast(ray, out hit, 20))
{
Inventory.Instance.PlaceItemToInventory(hit.collider.gameObject);
puzzle16Taken = true;
puzzlePartNumber += 1;
DontDestroyOnLoad(gameObject); //the object will be saved in the inventory
SaveLoad.Save(puzzlePartNumber, “AllPuzzles”); //increasing to 25
SaveLoad.Save(puzzle16Taken, “Puzzle16”);
Debug.Log(“puzzlePartNumber” + puzzlePartNumber);
}
}
this code doesn’t work and I don’t know, why. The implementation of SaveLoad.Save() has to take place after each changing.
Someone with an advice ?
Peter
Please use code tags to post code examples. This is hardly readable.
There is a sticky on this subforum if you need help finding out how to use code tags.
Sorry, I don’t find the “sticky” with tips how to use use. I see only “Add Tags”!?
Well it’s just about pressing the <> button here in the editor, then inserting the code there. But the sticky is, by definition, one of the upper most threads on this (scripting) subforum. Anyways here is the link: Using code tags properly
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
public class SaveLoad : MonoBehaviour
{
public static void Save<T>(T objectToSave, string saveName)
{
string path = Application.dataPath + "/SaveGames/";
Directory.CreateDirectory(path);
BinaryFormatter bF = new BinaryFormatter();
FileStream fS = new FileStream(path + saveName + ".dat", FileMode.Create);
try
{
bF.Serialize(fS, objectToSave);
Debug.Log("saved" + objectToSave);
}
catch(SerializationException exception)
{
Debug.Log("Save failed. Error: " + exception.Message);
}
finally
{
fS.Close();
}
}
public static T Load<T>(string saveName)
{
string path = Application.dataPath + "/SaveGames/";
BinaryFormatter bF = new BinaryFormatter();
T returnValue = default(T);
try
{
FileStream fS = new FileStream(path + saveName + ".dat", FileMode.Open);
returnValue = (T)bF.Deserialize(fS);
}
catch(SerializationException exception)
{
Debug.Log("Load failed. Error: " + exception.Message);
}
return returnValue;
}
public static bool SaveExists(string saveName)
{
string path = Application.dataPath + "/SaveGames/" + saveName + ".dat";
return File.Exists(path);
}
public static void SeriouslyDeleteAllSaveFiles()
{
string path = Application.dataPath + "/SaveGames/";
DirectoryInfo directory = new DirectoryInfo(path);
directory.Delete(true);
Directory.CreateDirectory(path);
}
}
and a part of the “class TakenObjects”
if (Physics.Raycast(ray, out hit, 20))
{
Inventory.Instance.PlaceItemToInventory(hit.collider.gameObject);
puzzle16Taken = true;
DontDestroyOnLoad(gameObject);
if (puzzle16Taken)
{
allPuzzles.puzzleName = "Puzzle16";
allPuzzles.puzzleTaken = true;
takenPuzzles.Add(allPuzzles);
puzzlePartNumber += 1;
}
SaveLoad.Save<List<MyPuzzles>>(takenPuzzles, "TakenPuzzles");
SaveLoad.Save<int>(puzzlePartNumber, "NumberPuzzles");
SaveLoad.Save<int>(takenPuzzles.Count, "NumberOfPuzzles");
}
}
I hope this helps.
Sorry, there is a last update with my code(see above). I have tried to use a class for the Puzzles and implement a
“public List takenPuzzles = new List();” and an object of MyPuzzles: “public MyPuzzles allPuzzles;”
[Serializable]
public class MyPuzzles
{
public string puzzleName;
public bool puzzleGenommen;
public MyPuzzles()
{ }
public MyPuzzles(string theName, bool genommen)
{
puzzleName = theName;
puzzleGenommen = genommen;
}
}
Now its resulting a new question:
why is saved only the last element of the list ? E.g. in room Kitchen take puzzle12, in bathroom puzzle02 and so on.
Now in the List should be puzzle12 and puzzle 02, but only saved is the last one (puzzle02). Of course this is not good, but where is the mistake ? Any advice for me, please.
Peter