I’m trying to get a save/load system going and want to affect the player position and rotation on a load. The weird thing is that while I can get the player’s rotation to change successfully, I can’t get the position to and I don’t know why.
I save the data in this class:
[System.Serializable]
//structure of players data
public class PlayerData
{
public float PosX { get; set; }
public float PosY { get; set; }
public float PosZ { get; set; }
public float QuatX { get; set; }
public float QuatY { get; set; }
public float QuatZ { get; set; }
public float QuatW { get; set; }
public PlayerData(Vector3 position, Quaternion quat)
{
this.PosX = position.x;
this.PosY = position.y;
this.PosZ = position.z;
this.QuatX = quat.x;
this.QuatY = quat.y;
this.QuatZ = quat.z;
this.QuatW = quat.w;
}
}
and use these functions to save/load it (i have the file writing down fine so I won’t include that)
I notice in SavePlayer playerPosition is a local variable that you are populating as you declare it on line 3 of your snippet. However in LoadPlayer you have a variable with the same name but the declaration and initialization of that variable are not in your snippet. This reads as fishy to me.
Can you share the rest of that script? I’m specifically interested in the declaration and initialization of “playerPosition”
//Save data should be serializable
[System.Serializable]
public class SaveData
{
public PlayerData ThePlayerData { get; set; }
//constructor to instantiate everything
public SaveData()
{
}
}
[System.Serializable]
//structure of players data
public class PlayerData
{
public float PosX { get; set; }
public float PosY { get; set; }
public float PosZ { get; set; }
public float QuatX { get; set; }
public float QuatY { get; set; }
public float QuatZ { get; set; }
public float QuatW { get; set; }
public PlayerData(Vector3 position, Quaternion quat)
{
this.PosX = position.x;
this.PosY = position.y;
this.PosZ = position.z;
this.QuatX = quat.x;
this.QuatY = quat.y;
this.QuatZ = quat.z;
this.QuatW = quat.w;
}
}
public class SaveManager : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
//if you want to see where this persistent data path is on your computer
//Debug.Log(Application.persistentDataPath);
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Q))
{
Save();
}
if(Input.GetKeyDown(KeyCode.E))
{
Load();
}
}
private void Save()
{
try
{
BinaryFormatter formatter = new BinaryFormatter();
//if the file is not there, we are going to create it. Creates file on harddrive
FileStream file = File.Open(Application.persistentDataPath + "/" + "SaveTest.dat", FileMode.Create);
SaveData data = new SaveData();
SavePlayer(data);
formatter.Serialize(file, data);
//need to close file or else there will be issues
file.Close();
}
catch (System.Exception) //catch exceptions so unity doesn't crash
{
//This will delete dave data if corrupted
}
}
private void Load()
{
try
{
BinaryFormatter formatter = new BinaryFormatter();
//if the file is not there, we are going to create it. Creates file on harddrive
FileStream file = File.Open(Application.persistentDataPath + "/" + "SaveTest.dat", FileMode.Open);
SaveData data = (SaveData)formatter.Deserialize(file);
//need to close file or else there will be issues
file.Close();
LoadPlayer(data);
}
catch (System.Exception) //catch exceptions so unity doesn't crash
{
//This will delete dave data if corrupted
}
}
private void SavePlayer(SaveData data)
{
Transform playerPosition = GameObject.Find("Player").transform;
//i have tried combos of position, local position, setting vector 3 to zero... nothing changes the actual position in the game
data.ThePlayerData = new PlayerData(playerPosition.localPosition, playerPosition.rotation);
}
private void LoadPlayer(SaveData data)
{
Transform playerPosition = GameObject.Find("Player").transform;
playerPosition.localPosition = new Vector3(data.ThePlayerData.PosX, data.ThePlayerData.PosY, data.ThePlayerData.PosZ);
playerPosition.rotation = new Quaternion(data.ThePlayerData.QuatX, data.ThePlayerData.QuatY, data.ThePlayerData.QuatZ, data.ThePlayerData.QuatW);
}
}
Thanks for sharing that. I know you said you were able to get rotation to work… But my current guess is that this property:
public PlayerData ThePlayerData { get; set; }
Is not serializing at all. Does BinaryFormatter actually serialize properties at all? I know Unity doesn’t by default.
A couple things I would try:
First, Debug.Log the values of the SaveData/PlayerData objects right after loading. Then at least you can verify if it’s an issue with loading the data or if it’s an issue of just moving your player based on the loaded data.
If the data is actually not loading properly, try turning the ThePlayerData property into a plain old field.
So the data supposedly is loading properly. I put some debugs before and after trying to change the transform and this is what i get
Debug.Log("Position Saved: " + data.ThePlayerData.PosX + ", " + data.ThePlayerData.PosY + ", " + data.ThePlayerData.PosZ);
Debug.Log("Current Player Position: " + playerPosition.localPosition);
playerPosition.localPosition = new Vector3(data.ThePlayerData.PosX, data.ThePlayerData.PosY, data.ThePlayerData.PosZ);
Debug.Log("Current Player Position Has Changed To: " + playerPosition.localPosition);
playerPosition.rotation = new Quaternion(data.ThePlayerData.QuatX, data.ThePlayerData.QuatY, data.ThePlayerData.QuatZ, data.ThePlayerData.QuatW);
but as you can see, clearly the position hasn’t changed at all. It’s still at -1.5, 0.1, -1,1. despite saying it’s been changed appropriately
I’ve also tried making ThePlayerData just “public PlayerData ThePlayerData;” but that doesn’t seem to change anything
Sorry my post freaked out for a hot second and I just fixed it. There is a photo where you can see the “Player” game object is highlighted in the hierarchy, as well as the transform saying its been changed but it hasn’t
Setting the animator.enabled to false didn’t seem to change anything. I even left it disabled the whole time and i could still rotate, but no position change
I’ve just tested instantiating a cube at the coordinates I set and the cube spawns correctly. Maybe I can delete the player object and instantiate it in the new area?
So I can correctly instantiate a new “Player” into the scene at the position and rotation, however this breaks all the links to everything so this is not the optimum solution. I wish I knew why this is getting held up
I’ve fixed it, but I have no idea why what I did worked. Basically, The object “Player” Was part of a “Game Essentials” prefab. Within the player parent object there was a child object that was an organizer for the player parts (graphics, cam, etc). I found with testing I could move that object, just not the top parent object. So I moved all the code and controller stuff that was on the parent object onto this child object, then moved the child out of the parent so it was it’s own thing. Now I can move it as expected.
Thanks for your help all this time! I did some weird stuff and it fixed it somehow. I’m not going to question it haha (i changed my post talking about the player controller to just explain what I did to fix it)