- Home /
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");
}
}
If you Debug.log(playerPos), what coordinates does it say? $$anonymous$$aybe you just simplified your code here but I don't see anywhere where you would instantiate your G$$anonymous$$ class in Player script. playerTransform.position = Sm.gm.playerPos; -> It could end up at the origin because the playerPos variable is never saved or always redeclared at new Vector3(0,0,0), which is the default value for a Vector3. Have you tried using static variables and/or the DontDestroyOnLoad() method on the G$$anonymous$$ script?
I didn't show it in my post, but I had a script called "Sm", short for "Static $$anonymous$$anager" in which Player and G$$anonymous$$ are declared as public static scripts. So I do have static variables, and I do have a DontDestroyOnLoad method on the same game object as the G$$anonymous$$ script, but on a different script. I'll update my post with the scripts I left out.
Why did you make a DontDestroyOnLoad class? Unity already has a DontDestroyOnLoad() method, besides, that script seems pretty faulty to me. Just put DontDestroyOnLoad(gameObject); in the Awake() method of Sm.cs. Also, is the Sm.cs script attached to a GameObject in the first scene? Another question also is that, why do you have a Scene1 if you save your position in Scene2?
Your pointers regarding DontDestroyOnLoad are noted, but I don't think that's causing the issue. But I am not saving my position in Scene 2. I save my position, and then on the next line I load scene 2. Originally, I was loading scene 2 first, but then I realized what I was doing and changed the order, but it made no difference, as when I went back to scene 1, the player's position was still not updating.
Answer by Freesmith · Jun 21, 2019 at 01:52 AM
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 :)
try adding this to your player class
private void Update()
{
Sm.gm.playerPos = playerTransform.position;
}
No, actually, I've got that on a different script on the same game object. The game object persists between the scenes fine. I just can't successfully update the player's position upon returning to scene 1.
hm , maybe try calling the SavePlayerPosition(); before loading the scene. like putting this line
Sm.gm.SavePlayerPosition();
before
Scene$$anonymous$$anager.LoadScene("Scene2");
Yeah, I did notice that, and i changed the order, but unfortunately, it is still doing the same thing.
Answer by unity_Y9AfbvAM22aTww · Jun 21, 2019 at 03:37 PM
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();
}
}
Answer by ShamimAkhter · Jun 22, 2019 at 07:01 AM
Use a scriptableObject to store the position in a vector3 variable. The data stored in a scriptableObject preset does not change between scenes.
Your answer
Follow this Question
Related Questions
crouch script 4 Answers
Transform angle to grid position 2 Answers
Return to Start Position 1 Answer
How to manage position of player sub objects 1 Answer
Problem with local position 3 Answers