Hey, we are building an FPS Puzzle game and we have multiple doors to unlock, a part of them with a plate and another part with a simple button, so we use two different scripts, one for doors unlocked with button and another script for the doors with a plate, but we want to save the unlocked doors in a JSON file, it works fine when we save the bool from the state of the puzzles, but then are all dors from the sort unlocked, did someone know an easy solution for the problem (duplicate the code we try to avoid).
Thank you for a fast answer, because we have to submit it on Friday this week.
(Unity version 2019.3.06 + C#)
Saving the bool is what you want to do. You cant save the game objects themselves, rather their individual data. Like location, rotation, size, and of course bools, int, floats, etc… I personally use binary save functions.
namespace GameSaving
{
public class SaveLoad : MonoBehaviour
{
#region DoorfVariables
//doors open?? (Propertys)
private bool _door1Open;
private bool _door2Open;
#endregion
private static string _path;
private static string _dir;
[SerializeField] private GameObject _scriptDoorRoom1 = null;
[SerializeField] private GameObject _scriptDoorBigStorageRoom = null;
private Room1 _doorRoom1;
private Room1 _doorBigStorageRoom;
private void Awake()
{
//_saveMaster = FindObjectOfType<SaveMaster>();
PlayerMovement.controller = GameObject.FindGameObjectWithTag("Player").GetComponent<CharacterController>();
}
private void Start()
{
_path = Path.Combine(Application.dataPath, "SaveFiles/SaveFile1.json");
_doorRoom1 = _scriptDoorRoom1.GetComponent<Room1>();
_doorBigStorageRoom = _scriptDoorBigStorageRoom.GetComponent<Room1>();
}
public void SaveGame()
{
_door1Open = _doorRoom1.PuzzleSolved;
PlayerMovement.controller = PlayerMovement.controller;
GameInfo gameInfo = new GameInfo(PlayerMovement.controller, _door1Open, _door2Open);
string _texto = JsonConvert.SerializeObject(gameInfo, Formatting.Indented);
_dir = Path.Combine(Application.dataPath, "SaveFiles");
//KK: if no directory exists, it creates one
if (!Directory.Exists(_dir))
{
Directory.CreateDirectory(_dir);
}
//KK: writes the saved string into the file
File.WriteAllText(_path, _texto);
}
public void LoadGame()
{
//KK: path from where the game loads the data
_dir = Path.Combine(Application.dataPath, "SaveFiles");
//KK: if no save game path exists it creates a path
if (!Directory.Exists(_dir))
{
Directory.CreateDirectory(_dir);
}
if (!File.Exists(_path))
{
return;
}
//KK: saves path in a screen
string _texto = File.ReadAllText(_path);
//KK: loads the data from the path(json file)
var _infoLoad = JsonConvert.DeserializeObject<GameInfo>(_texto);
//KK: disables the charactercontroller to be able to overwrite its position
PlayerMovement.controller.enabled = false;
// KK: loads the saved position from the player
PlayerMovement.controller.transform.position = _infoLoad.Pos;
//KK: activates the charactercontroller after the saved position is loaded
PlayerMovement.controller.enabled = true;
_doorRoom1.PuzzleSolved = _infoLoad.Door1Open;
}
}
public class GameInfo
{
public Vector3 Pos;
#region DoorOpenVars
public bool Door1Open;
public bool Door2Open;
#endregion
public GameInfo(CharacterController pplayer, bool _door1Open, bool _door2Open)
{
//saves the position from the player
Pos = PlayerMovement.controller.transform.position;
Door1Open = _door1Open;
Door2Open = _door2Open;
}
}
}
Are you familiar with arrays? I ask because using a bool array should solve this problem and I don’t see you using any arrays in your code. The GameInfo class could take a bool[ ] instead of different bool arguments, and then you serialize the array. So, instead of variables like bool _door1Open; bool _door2Open;, you have a single variable bool[ ] _doorOpen = new bool[10]; (10 is an example number of doors), and you reference them by index _doorOpen[0] = true;
Thank you, I will try it, but we decided for the first to leave it only with the check points while a game run, because we have lots more puzzles like energy cells… I would be to complex to handle it till friday, but I definitly try it out in my next game
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Game
{
public static Game current = new Game();
// Store your variables here such as ->
bool _fakeBool;
float _fakeFloat;
int _fakeInt;
// ETC
}
Then the actual magic here
SaveLoad.cs
using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
public static class SaveLoad
{
public static void SaveGame()
{
BinaryFormatter bf = new BinaryFormatter();
if (File.Exists(Application.persistentDataPath + "/SavedGame.dat"))
{
FileStream file = File.Open(Application.persistentDataPath + "/SavedGame.dat", FileMode.Open);
Game game = new Game();
game._fakeBool= Game.current._fakeBool;
bf.Serialize(file, Game.current);
file.Close();
}
else
{
FileStream file = File.Create(Application.persistentDataPath + "/SavedGame.dat");
Game game = new Game();
game._fakeBool= Game.current._fakeBool;
bf.Serialize(file, Game.current);
}
}
public static void LoadGame()
{
if (File.Exists(Application.persistentDataPath + "/SavedGame.dat"))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/SavedGame.dat", FileMode.Open);
Game game = (Game)bf.Deserialize(file);
file.Close();
Game.current._fakebool= game._fakeBool;
}
}
public static void DeleteFile()
{
string filePath = Application.persistentDataPath + "/SavedGame.dat";
// check if file exists
if (!File.Exists(filePath))
{
}
else
{
File.Delete(filePath);
}
}
}
Then at the beggining of the game, on splash or where ever, call →
SaveLoad.LoadGame();
And after each time you change a variable, call →