How to save objects with the same script separate

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#)

What does your code look like…

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.

Yes, but the rotation, size, location,… is constant, only the lock state changes

This is the code, which is for the doors with the buttons

public class Room1 : MonoBehaviour
{
    [Header("Exit light")]
    [SerializeField] private GameObject _exitLight = null;
    [SerializeField] private Material _green = null;
    [SerializeField] private Material _red = null;
    [SerializeField] private Light _pointLight = null;

    [Header("Player")]
    [SerializeField] private GameObject _player = null;

    [Header("Button")]
    [SerializeField] private AudioSource _buttonClick = null;
    
  
    [Header("Door")]
    [SerializeField] private GameObject _door = null;
    [SerializeField] private Animator _animator = null;
    [SerializeField] private AudioSource _doorOpen = null;
    [SerializeField] private AudioSource _doorClose = null;

    public bool PuzzleSolved  //KK: for the saving system
    {
        get { return _puzzleSolved; }
        set { _puzzleSolved = value; }
    }

    private bool buttonIsPressed = false;
    private bool _puzzleSolved = false;

    private bool _doorIsOpen;

    [HideInInspector] public float distance;
    [HideInInspector] public float maxDistance = 6f;
   
    void OnMouseOver()
    {
        if (Input.GetMouseButtonDown(0))
        {
            buttonIsPressed =  PressButton(transform.gameObject, buttonIsPressed, _buttonClick, true);                   
        }
    }

    //This function checks if the player is near to the pressed button.
    //If the player clicks on the button, it switches the state of the button and returns the current state
    public bool PressButton(GameObject button, bool buttonIsPressed, AudioSource _buttonClick, bool DistanceIsNeeded)
    {
        if (DistanceIsNeeded)
        {
            distance = Vector3.Distance(button.transform.position, _player.transform.position);
        }
        else
        {
            distance = 0;
        }

        if ( !buttonIsPressed && distance <= maxDistance)
        {

            button.transform.position += button.transform.forward * 0.1f;
            buttonIsPressed = true;
            _buttonClick.Play();
           
        }
        else if ( buttonIsPressed && distance <= maxDistance)
        {
           
            button.transform.position -= button.transform.forward * 0.1f;
            buttonIsPressed = false;          
            _buttonClick.Play();
        }
        return buttonIsPressed;
    }

    //checks if the button is pressed and opens the door of room 1
    void Update()
    {
        if (buttonIsPressed)
        {
            _puzzleSolved = true;
            SetColorToGreen(_exitLight, _pointLight);
        }
        else
        {
            _puzzleSolved = false;
            SetColorToRed(_exitLight, _pointLight);
        }

        _doorIsOpen = OpenTheDoor(_door, _animator, _puzzleSolved, _doorIsOpen, _doorOpen, _doorClose);
       
    }


    //Set exitLight colors
    //to green
    public void SetColorToGreen(GameObject exitLight, Light pointLight)
    {
        Renderer Light = exitLight.GetComponent<Renderer>();
        Light.material.SetColor("_Color", _green.color);
        pointLight.color = _green.color;
    }
    //to red
    public void SetColorToRed(GameObject exitLight, Light pointLight)
    {
        Renderer Light = exitLight.GetComponent<Renderer>();
        Light.material.SetColor("_Color", _red.color);
        pointLight.color = _red.color;
    }


    //when puzzle is solved, check if player is nearby and open the door
    public bool OpenTheDoor(GameObject door, Animator animator, bool puzzleSolved, bool doorIsOpen, AudioSource doorOpen, AudioSource doorClose)
    {
        distance = Vector3.Distance(_player.transform.position, door.transform.position);
               
        if (puzzleSolved && distance <= maxDistance)
        {
            animator.SetBool("character_nearby", true);
            door.GetComponent<Collider>().enabled = false;
            doorOpen.Play();
            doorIsOpen = true;
        }
        else if (doorIsOpen)
        {              
            animator.SetBool("character_nearby", false);
            door.GetComponent<Collider>().enabled = true;
            doorClose.Play();
            doorIsOpen = false;
        }

        return doorIsOpen;
    }
}

and this is the code for save the game

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

This is whay i use to save my stuff…

Game.cs

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 →

SaveLoad.SaveGame();
1 Like