Set location Rotation when changing a scene
I'm working on an virtual museum. The user find himself inside a museum hall (scene 1) and then he is able to cross different paintings and then being redirected to a different scene in each painting. My question is how can i set the position and the rotation of the player when he comes back to the main hall so he would be next to the painting he entered and not from the beginning? I saw Dontdestroyonload functions and static functions, but i dont know what's best to use.
Thank you for helping a helpless girl !
Dontdestroyonload in your case could not be the "cleanest" solution.
This is the definition in Unity documentation : "$$anonymous$$akes the object target not be destroyed automatically when loading a new scene."
This is not exactly what you want, because you actually don't need to have a transform object alive in your "PaintingScene", all you need it get back a position and rotation when you are back in the main hall.
It could be interesting for you to learn Dontdestroyonload, but a bad use of this is as negative for your project as a bad use of statics. So I don't think there is a best solution in your case, you just take the one you are more comfortable with.
Answer by Blue-Cut · Apr 15, 2016 at 03:33 PM
[EDIT] The easiest way to perform this is to use a static variable. A static variable will be global to your whole project and not your current scene. The solution you are looking for is very easy to implement, but there are several things to do.
First : the MainHall scene. You have 3D paintings in it, these 3D paintings are gameobject put in your scene. Into these gameobject, put a child gameObject called "Spawn", and place the "Spawn" at the position and rotation you want for this specific painting. Then, you should have a script like this on your painting object :
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
// Represents the painting
public class PaintingSelector : MonoBehaviour
{
// This is the Spawn object inside the painting object
public Transform spawn;
void Start()
{
// At start, set the spawn transform by looking in painting's children
spawn = transform.FindChild ("Spawn");
}
void OnMouseDown()
{
// When you select the painting, set the statics then load the next scene
Statics.firstPlayerPosition = spawn.position;
Statics.firstPlayerRotation = spawn.eulerAngles;
SceneManager.LoadScene ("PaintingScene");
}
}
Now, your Statics file. It constains the position and rotation you want to keep between the two scenes:
using UnityEngine;
using System.Collections;
public class Statics
{
// This is used for the very first time you enter the MainHall, there is no seen painting at this moment
public static bool firstTimeInHallPassed = false;
// Position and rotation of the player next time you enter the MainHall
public static Vector3 firstPlayerPosition = Vector3.zero;
public static Vector3 firstPlayerRotation = Vector3.zero;
}
And now, the player. When the scene MainHall starts, you want to put the player at the position defined by your Statics, but only if you are coming from a PaintingScene, not the first time you play the game :
using UnityEngine;
using System.Collections;
public class Player : MonoBehaviour
{
void Start ()
{
if (Statics.firstTimeInHallPassed)
{
transform.position = Statics.firstPlayerPosition;
transform.eulerAngles = Statics.firstPlayerRotation;
}
else
{
Statics.firstTimeInHallPassed = true;
}
}
}
As your problem is like making a complete project with several scripts involed, I made a little Unity project to be sure that my solution is working. So I can tell you : it's working. So if you have a problem and it's not working for you, it means that you have done a little mistake somewhere and I can help you to find it.
Seems like a good idea.. can you walk me through it.. (i'm new in coding). So i should create statics variables of all the positions and rotations i want for the different paintings i'm crossing and then i call them when i enter the scene from each of them?
I have a trigger collider in each of the painting that transport me to the main hall scene :
function OnTriggerEnter (other : Collider) {
if (other.gameObject.tag == "Player"){
Scene$$anonymous$$anager.LoadScene ("$$anonymous$$ainHall");
}
}
No, you don't need to create statics for all your painting positions, because you already know these positions : they are in the transform of your painting objects, in your scene. The only position and the only rotation you need to keep from one scene to another, it the position and rotation of the painting you have selected before loading the other scene.
I don't know what time it is at your place, but it's very late on my side, so I will read carefully all your post tomorrow to be sure that I understand what you want, then I'll help you with this if you still need help ;)
What about using many Spawnpoints in the main hall attached to empty objects with the desired position and rotation for eahc painting entrance and using transform when loading the main hall level from the paintings scene? would that work?
I just tested a working solution, I put a new reply in a $$anonymous$$ute
You need to understand what you are doing. I suggest you to use statics because it's a very simple way to keep a value when you leave a scene, and a simple way to do something will help you faster if you are new in coding.
But in this case, a static is "a value for a property that is global to my project and that I could want use at any time". So in your case, you have only two values : the vector3 for the position and the Vector3 for the rotation you want to set to your player when you enter the "HallScene". All the other values, that are specific to your paintings, you never need them. They are just get when you use the method that select a specific painting.
"What about using many Spawnpoints in the main hall attached to empty objects with the desired position and rotation for eahc painting entrance and using transform when loading the main hall level from the paintings scene? would that work?"
This sounds better. But you don't need to attach you Spawnpoints to empty gameobject, you should put them into their painting : "Painting" has a child "Spawn". This way, when you select a painting, you can get its child and see the transform of this child.
Ah, just edit my reply for you ^^ Try to do it by yourself if my explain is clear. If you use the code I wrote, please tell me if you don't understand something, is very important that you understand what you are doing.
I attach the first script to my painting object, and the last one to my player object and the static one shouldn't be on any object?
Yes indeed. When you create a new script with Unity, it inherits "$$anonymous$$onoBehaviour" by default. A $$anonymous$$onoBehaviour is a class that is supposed to be attached on a GameObject. And the trick is precisely here.
GameObjects exist in a specific scene. If you change your scene, so you don't have access to the GameObjects of your old scene, and when you enter the previous scene again, its state is reset.
The purpose of the Statics class is to be above all this system, above the scenes and independant from the GameObjects it contains. When you are working with a complex Unity project, you can find a lot of reasons to work with classes that are not inheriting from $$anonymous$$onoBehaviour.
You're a genius ! worked like a charm finally ! just one thing the rotation, even though i changed the rotation of my spawn object it's not changing it for the player (position worked great)
Answer by Kurdle_4855 · Apr 15, 2016 at 03:31 PM
You could save the players location and rotation when they go into another scene and then set it when they exit
Answer by Happy-Zomby · Apr 15, 2016 at 03:20 PM
Hi, the easiest will be to just save the position and rotation to playerPrefs before you leave the main hall and then load them back when you come back to the main hall. Something like this:
//in scene 1 on a save button
public Transform player;
void Save ()
{
PlayerPrefs.SetFloat("PositionX", player.position.x);
PlayerPrefs.SetFloat("PositionY", player.position.y);
PlayerPrefs.SetFloat("PositionZ", player.position.z);
//repeat similar for rotation
}
void Load ()
{
player.position = new Vector3(PlayerPrefs.GetFloat("PositionX"),PlayerPrefs.GetFloat("PositionY"),PlayerPrefs.GetFloat("PositionZ"));
//repeat similar for rotation
}
then you can run save script before you leave your scene and run load on the Start() when you come back to your main hall scene. - or just put the whole load code in start and no need to call it. hope that helps,
I didn't think about using PlyerPrefs like this, but I recommand the static method.
Correct me if I'm wrong, but PlayerPrefs it's about writing in a file. You do a kind of basic save that is still considered when you replay the game. Is that what you want ?
If the behaviour with PlayerPrefs is not working for you, check out my method with the static, it will work and it's as easy as this.
Good point - you would need to reset/clear the player prefs when you start a new game (visit) but you could also leave the museum(game) and restart at the same place next time.
I don't use much static so I can say which will be the easiest to implement - I'm sure Blue Cut's solution will work fine - so just pick the one which seems the easiest for you
I think the real Q is whether the OP is learning Unity, or just wants to get this done. static is probably the easiest "just type it and shut up" solution, but seeing statics early makes most people into worse programmers. PlayerPrefs have better examples (including how to store a rotation,) and make more sense. DontDestroyOnLoad is a more useful trick in general, and is a good way to learn about reaching out to other objects -- maybe the best solution for someone using this as a learning project.
I hear your point, but I don't agree when you say that PlayerPrefs make more sense. PlayerPrefs sense is to set up some player prefs, and in the current case, we are not talking about setting some player prefs but about keeping a property from one scene to another.
A good use of statics is the same thing than a good use of any other coding feature. You learn it with time.
Ok for the DontDestroyOnLoad, you should suggest a reply based on it.
Your answer
Follow this Question
Related Questions
Singleton GameManager with DontDestroyOnLoad acting weird 0 Answers
save variable from previous scene 2 Answers
Destroyed object in DontDestroyOnLoad does not recreate in its main scene 0 Answers
Can I create a scene DontDestroyOnLoad in editing mode?? 0 Answers
Dropdown menu: how to make colour change across multiple scenes 0 Answers