Having terrible trouble with saving/loading player position

So I’ve looked at the beginner tutorial for how to save and load small bits of information using player prefs, but my problem is a little unique, in that I want my player’s exact position saved when they perform a certain action in game, and it only loads when the player dies. I know that there are other questions like this that have been answered, but I couldn’t make much sense out of the answers, either because it was in javascript, or it was done in a way that requires more in depth knowledge on the subject.

So, I was wondering if you guys could help me by taking a look at these few excerpts of my scripts and tell me what I need to do to save my player’s position, and what do I need to do to load it back up.

This is the script that contains data:

using aUnityEngine;
using System.Collections;
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;


public class GameControl : MonoBehaviour {

	public static GameControl control;
	public GameObject player;


	void Awake(){
		if (control == null) {
			DontDestroyOnLoad (gameObject);
			control = this;
		} else if (control != this) {
			Destroy (gameObject);
		}

	}
	public void Save()
	{
		BinaryFormatter bf = new BinaryFormatter ();
		FileStream file = File.Create (Application.persistentDataPath + "/playerInfo.dat");

		PlayerData data = new PlayerData ();
		data.player = player;

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

	public void Load()
	{
		if (File.Exists (Application.persistentDataPath + "/playerInfo.dat")) {
			BinaryFormatter bf = new BinaryFormatter ();
			FileStream file = File.Open (Application.persistentDataPath + "/playerInfo.dat", FileMode.Open);
			PlayerData data = (PlayerData)bf.Deserialize (file);
			file.Close ();
			player = data.player;
		}
			
	}

}

[Serializable]
class PlayerData
{
	public GameObject player;
}

This is the script that causes a save to occur:

void Update () {

		//chestclick
		ray = Camera.main.ScreenPointToRay (Input.mousePosition);
		if (Physics.Raycast (ray, out hit)) {
			if (Input.GetButtonDown ("Fire1")) {
				if (hit.transform.name == "Chest") {
					GameControl.control.Save();
				}
			}
		}

And this is the script that loads the data:

void OnTriggerEnter(Collider other)
	{
             if (other.gameObject.CompareTag ("Player")) {
			GameControl.control.Load();
		}
}

Keep in mind that everything seems to be set up correctly, for I am getting no errors, save for when the save/load parts of the scripts activate.

You are serializing a simple data class “PlayerData” using C#'s builtin BinaryFormatter. That is fine - in theory.

However, you can not serialze a GameObject reference there. GameObject is an unity class, mostly implemented in C++. You can not directly try to serialize such a complex class. In the very best, you will serialize all C# parts of the player reference (such as internal pointer and handles used by C++) and it might restore the reference to the original object (but only the reference, not the actual values of that object).

In the worst case, it will simply crash because the said handles and internal pointers are not valid anymore.

So what can you serialize using BinaryFormatter? Basically all standard C# datas and some very simple structs that also need to be declared [Serializable]. Not even Unity-structs like a Matrix3x3 or a Vector3 is serializable with BinaryFormatter.

Edit: After some comments, the easiest way is to abandon BinaryFormatter and use JsonUtility that ships since Unity 5.3. This tool can convert any unity-serializable object properties into JSON text format and back. The code example has been updated accordingly. Note, that JsonUtility still can not serialize complex Unity-intern things like a whole GameObject. But it can serialize basic structs like Vector3, Quaternion, Color etc… (It also can serialize self-made MonoBehaviours, although you need to use AddComponent + FromJsonOverwrite to deserialize these)

First, think about what exactly it is you want to restore? What can change of the player that should be reset? You wrote already that you like to save/restore the players position. Also its rotation? Can the scale change?

Then just set/read these exact primitive values from PlayerData.

 public void Save()
 {
     PlayerData data = new PlayerData ();
     data.playerPosition = player.transform.position;
     data.playerRotation = player.transform.rotation;
     string json = JsonUtility.ToJson(data);
     File.WriteAllText(Application.persistentDataPath + "/playerInfo.dat", json);
 }

 public void Load()
 {
     string json = File.ReadAllText(Application.persistentDataPath + "/playerInfo.dat");
     PlayerData data = JsonUtility.FromJson<PlayerData>(json);
     player = data.player;
     player.transform.position = data.playerPosition;
     player.transform.rotation = data.playerRotation;
 }

 [Serializable]
 class PlayerData
 {
     public Vector playerPosition;
     public Quaternion playerRotation;
 }

Of course, the variable “player” needs to be ready and set up correctly in Load before you read out the serialized values. Whether you can just reuse the currently deceased player or you have to completely recreate him is up to you to decide (in the latter, you might think about spawning the player out of some prefab when the game starts too - just to keep things consistent).

Dude where you + the data path i learned that you should not use + but use , instead

soo instead off string json = File.ReadAllText(Application.persistentDataPath + “/playerInfo.dat”);
do string json = File.ReadAllText(Application.persistentDataPath ,“/playerInfo.dat”);