Save and Load Player Position JSON

Hi,

I tried dozens of strategies to save and load player position through JSON, but all that is loaded is the player’s starting position, and not when I save the game. The save file is correct. But it cannot load correctly. It’s coming from the load method. Can anyone tell me how to edit it? The whole code is attached. And please don’t tell me anything like another strategy (worst of all, PlayerPrefs) and please don’t tell me I should do it on my own because doing so is currently forcing me to pull my hair out. The reason that I need only JSON is because I found a way to encrypt the stats for my game.

Save.cs:

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

[Serializable]
public class Save
{
    public int scoreNum;
    public int livesNum;

    public float posX;
    public float posY;

    public string sceneName;
}

PauseScreen.cs:

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class PauseScreen : MonoBehaviour
{
    public static PauseScreen instance;

    public GameObject pauseCanvas;
    
    public bool stateLoaded;

    public bool isPaused;

    public GameObject player;

    public Scene scene;

    public int lives;

    public int score;

    public CountdownTimer ct;

    static readonly string SAVE_FILE = "player.json";

    void Awake()
    {
        pauseCanvas.gameObject.SetActive(false);
        isPaused = false;
        ct = FindObjectOfType<CountdownTimer>();
        scene = SceneManager.GetActiveScene();
        name = scene.name;
        player = GameObject.FindGameObjectWithTag("Player");
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            if (isPaused)
            {
                Resume();
            }
            else
            {
                Pause();
            }
        }
    }

    public void Resume()
    {
        pauseCanvas.gameObject.SetActive(false);
        Time.timeScale = 1;
        isPaused = false;
    }

    public void Pause()
    {
        pauseCanvas.gameObject.SetActive(true);
        Time.timeScale = 0;
        isPaused = true;
    }

    public void MainMenu()
    {
        Resume();
        SceneManager.LoadScene("MainMenu");
    }

    public void StartScreen()
    {
        Resume();
        SceneManager.LoadScene("Intro");
    }

    public void SaveByJSON()
    {
        Save save = new Save();
        save.scoreNum = ScoreSystem.score;
        save.livesNum = LivesSystem.lives;
        save.posX = player.transform.position.x;
        save.posY = player.transform.position.y;
        save.sceneName = SceneManager.GetActiveScene().name;

        string jsonString = JsonUtility.ToJson(save);

        string fileName = Path.Combine(Application.persistentDataPath, SAVE_FILE);

        if (File.Exists(fileName))
        {
            File.Delete(fileName);
        }

        File.WriteAllText(fileName, jsonString);

        Resume();
        Debug.Log("Your game has been saved to " + fileName + ".");
    }

    public void LoadByJSON()
    {
        string fileName = Path.Combine(Application.persistentDataPath, SAVE_FILE);
        if (File.Exists(fileName))
        {
            string json = File.ReadAllText(fileName);
            Save save = JsonUtility.FromJson<Save>(json);
            
            ct.ResetTime();
            
            StartCoroutine("loadScene");
            Resume();
            Debug.Log("Your game has been loaded.");
        }
        else
        {
            Debug.Log("NOT FOUND FILE");
        }
    }

    public IEnumerator loadScene()
    {
        string fileName = Path.Combine(Application.persistentDataPath, SAVE_FILE);
        string json = File.ReadAllText(fileName);
        Save save = JsonUtility.FromJson<Save>(json);
        SceneManager.LoadScene(save.sceneName, LoadSceneMode.Single);
        Vector2 newPos = new Vector2(save.posX, save.posY);
        AsyncOperation async = SceneManager.LoadSceneAsync(save.sceneName);

        while (!async.isDone)
        {
            yield return null;
        }

    }
}

Sincerely,
burchland2

The problem is with both LoadByJSON() and loadScene().

Now, we don’t see where you call LoadByJSON, but assuming you do call it, it looks like you load contents into save on row 134. But you never set the values somewhere, you just throw away the local variable save and proceed with StartCoroutine(“loadScene”) on row 138. That is a dangerous thing because it will not run immediately, but will begin running the next frame/update since it is a coroutine. There you load another local variable save from the same json-file and I assume that this is where the values are really put to use.

So in row 139, Resume() is run before loadScene() has run anything… and in row 154 you do not put the values to use, you just throw it away.

I suggest something like this:

bool hasLoaded = false;
void Update()
{
    if(hasLoaded)
    {
        //do stuff that can be done after scene has loaded
    }
    //...
}
//...
public IEnumerator loadScene()
{
    //load the JSON-file into save once
    string fileName = Path.Combine(Application.persistentDataPath, SAVE_FILE);
    string json = File.ReadAllText(fileName);
    Save save = JsonUtility.FromJson<Save>(json);

    //load one scene async
    AsyncOperation async = SceneManager.LoadSceneAsync(save.sceneName);
    while (!async.isDone)
    {
        yield return null;
    }
    
    //put other stuff in the JSON-file to use
    //...
    
    Resume();
    hasLoaded = true;
    Debug.Log("Your game has been loaded.");
}