Search code examples
c#unity-game-enginesavepositionload

Object's position & rotation is not getting saved / loaded (Unity Engine)


I need to save the player's position and rotation in-game. I use Binary Formatter and 2 buttons: 'Save' and 'Load' for this purpose. The script saves public Vector3 data if I write it down manually, save it, and then load the scene again. However, the player (just a cube) does not change its position and rotation. To fix this, I added:

void FixedUpdate()
    {
        position = player.transform.position;
        rotation = player.transform.rotation;
    } 

But that did not help. I use 2 scripts in order to make this work:

Player.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    public GameObject player;
    public Vector3 position;
    public Quaternion rotation;

    void FixedUpdate()
    {
        position = player.transform.position;
        rotation = player.transform.rotation;
    }

    public void Save()
    {
        SaveLoadManager.SavePlayer(this);
    }

    public void Load()
    {
        float[] loadedStats = SaveLoadManager.LoadPlayer();

        Vector3 loadedPos = new Vector3(loadedStats[0], loadedStats[1], loadedStats[2]);
        Vector3 loadedRot = new Vector3(loadedStats[3], loadedStats[4], loadedStats[5]);

        player.transform.position = loadedPos;
        player.transform.rotation = Quaternion.Euler(loadedRot);
    }
}

SaveLoadManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

public static class SaveLoadManager
{
    public static void SavePlayer(Player player)
    {
        BinaryFormatter bf = new BinaryFormatter();
        FileStream stream = new FileStream(Application.persistentDataPath + "/player.save", FileMode.Create);

        PlayerData data = new PlayerData(player);

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

    public static float[] LoadPlayer()
    {
        if (File.Exists(Application.persistentDataPath + "/player.save"))
        {
            BinaryFormatter bf = new BinaryFormatter();
            FileStream stream = new FileStream(Application.persistentDataPath + "/player.save", FileMode.Open);

            PlayerData data = bf.Deserialize(stream) as PlayerData;

            stream.Close();
            return data.stats;
        }
        else
        {
            Debug.LogError("File does not exist.");
            return new float[6];
        }
    }
}

[Serializable]
public class PlayerData
{
    public float[] stats;

    public PlayerData(Player player)
    {
        stats = new float[6];

        stats[0] = player.position.x;
        stats[1] = player.position.y;
        stats[2] = player.position.z;

        stats[3] = player.rotation.x;
        stats[4] = player.rotation.y;
        stats[5] = player.rotation.z;
    }
}

I'm quite new to Save-Load systems and Binary Formatting, so I hope you'll give me a hand.

Thanks in advance!

A GIF demonstrating the problem.

If someone else encounters a similar problem: besides adding the code in the Answer below, I also changed player.transform.rotation.(x/y/z); to player.transform.eulerAngles.(x/y/z); in SaveLoadManager.cs to make rotation work.


Solution

  • I'm not sure if I'm missing something, but I don't see anywhere in your Load() method that actually sets the Player's position to the loaded values. Instead it looks like you're passing the loaded values into unnecessary variables, then overwriting those constantly in FixedUpdate().

    Maybe try something like:

       public void Load()
        {
            float[] loadedStats = SaveLoadManager.LoadPlayer();
            
            Vector3 loadedPos = new Vector3(loadedStats[0], loadedStats[1], loadedStats[2]);
            Vector3 loadedRot = new Vector3(loadedStats[3], loadedStats[4], loadedStats[5]);
            player.transform.position = loadedPos ;
            player.transform.rotation = Quaternion.Euler(loadedRot);
    
        }
    

    And you can just get rid of the position and rotation variables on the Player script.