Unable to save the player's position between scenes

Hey Guys,

I’m making a game in which the player moves around in a scene, and at certain points, the scene changes, and when it returns to the original scene, the player needs to be placed at the position in which they were at when the scene changed. The way I’m attempting to do it is to cache the player position in a vector3 that is in a script on a persistent game object that isn’t destroyed between scenes. When the game returns to the first scene, the player position is set to be equal to the vector3 that is holding its last position. But for the life of me, I cannot get it to work. The player always ends up at the origin every time.

Here is my code. Please let me know what I’ve done incorrectly.

A “static manager” script

public class Sm : MonoBehaviour
{
    public static Player player;
    public static GM gm;
    
}

A DontDestroyOnLoad script to keep the game manager object persistent

public class DontDestroyOnLoad : MonoBehaviour
{
    public static DontDestroyOnLoad Instance { get; private set; }
    
    void Awake()
    {
        if(Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
    }
}

The player script

public class Player : MonoBehaviour
{
    public Transform playerTransform;

    private void Awake()
    {
        Sm.player = this;
    }

    private void Start()
    {
        playerTransform.position = Sm.gm.playerPos;
    }
}

The persistent game object

public class GM : MonoBehaviour
{
    // this is the persistent game object script
    public Vector3 playerPos;

    private void Awake()
    {
        Sm.gm = this;
    }

    public void SavePlayerPosition()
    {
        playerPos = Sm.player.playerTransform.position;
    }
}

The script used to move between scenes

public class ButtonManager : MonoBehaviour
{
    public void Scene1()
    {
        SceneManager.LoadScene("Scene1");
    }

    public void Scene2()
    {
        Sm.gm.SavePlayerPosition();
        SceneManager.LoadScene("Scene2");
    }
}

Hi, you need to add this line to the awake method

DontDestroyOnLoad(this.gameObject);

in the persistnet game object script


also , i suspect that when a new scene is loaded your sm class doesn’t recognize the gm reference,
and that in the awake method of sm class you should try to find persisted game object with gm class on it and assign it to sm.gm , unless the sm or gm is static :slight_smile:


try adding this to your player class

  private void Update()
    {
        Sm.gm.playerPos = playerTransform.position;
    }

You can use a little static system and avoid the DontDestroyOnLoad and, also avoid that kind of issues

public struct PlayerData
{
    public Vector3 position;
    public Quaternion rotation;
}

public class StaticData
{
    public static StaticData Instance {get;} = new StaticData();
    private StaticData()
    {
        playerData = new PlayerData();//the new is just in case you want to change the struct to a class
        playerData.position = Vector3.zero;
        playerData.rotation = Quaternion.identity;            
    }    
    public PlayerData playerData;
}

public class Examplo : MonoBehabiour
{
    
    void Start()
    {
        //takes the data from the StaticSystem
        transform.position = StaticData.Instance.playerData.position;
        transform.rotation = StaticData.Instance.playerData.rotation;
    }

    private PlayerData GetData()
    {
        return new PlayerData
        {
            position = transform.position,
            rotation = transform.rotation
        };
    }

    void Update()
    {
        //stores the current data on the static system
        StaticData.Instance.playerData = GetData();
    }
}

Use a scriptableObject to store the position in a vector3 variable. The data stored in a scriptableObject preset does not change between scenes.