- Home /
How to store character coordinates and quest progress between scenes?
Hello, I thought that this might probably be the most common problem with fresh Unity users, so I've been looking for the whole day in here and found some bits. However it's hard to put them together and make them work.
So it would be great if anyone could help me out and hopefully this will help others with a similar problem as well.
Let me start with how my level is structured. I have 1 main scene (like a hub) and 5 small scenes (interiors) which are accessed through doors in different locations on the main scene. Then I have an invisible box collider in front of these doors. When the PC collides with that box a text of the location behind the door in displayed in the corner of the screen and when the player hits "e" the new scene is loaded. Here is my code for that:
var LocText: Texture2D; var locRec: Rect = Rect (0, 0, 0, 0); var locName =0;
function OnTriggerStay (newLevel : Collider) { locRec = Rect (0,(Screen.height/2) + (Screen.height/5), Screen.width/2.5, Screen.height/6);
if (newLevel.gameObject.name == "PC") { locName =1; if (Input.GetKeyDown("e")) { locName = 0; Application.LoadLevel ("Dock_Arms"); } } }
function OnTriggerExit (newLevel : Collider) { locName =0; }
function OnGUI () { if (locName) { GUI.DrawTexture(locRec, LocText); } }
I ended up with copying the main scene 5 times and set the character in front of the correct door in each scene. So when the player exits interior 1 a main scene is loaded where the PC stands next to the door leading to interior 1 and so on. It works but that's not how it should be done. What I want is to have one main scene. What I need to know is how can I: -Keep character coordinates on the main scene when entering an interior. -Add rotation to these coordinates so that when I exit the interior, the door is behind PC's back. -Set a start location in the new scene for the PC to appear. -Not loose data on the quest progress. So that the NPC know that I've talked to them after going to another scene and back. -Keep items. If I take a key item from one scene, it wont be there any more after returning to that place from another scene.
So that's what I'm struggling with, hope to hear from someone! Thanks in advance!
Answer by demize2010 · May 20, 2011 at 10:49 AM
Hi man, check out static variables or even better PlayerPrefs for persistent data sotrage;)
http://unity3d.com/support/documentation/ScriptReference/PlayerPrefs.html
I notice there is no Vector3 type, so you will probably want to store 3 floats for XYZ location.
You can set ints, strings and floats for all other bits of data you need to track quest progress.
Answer by matcon · May 20, 2011 at 06:11 PM
Hry, thank you for your answer!
So should I do it somehow like this?
1 [in collision area] press "e" (for interaction in my game).
2 send Vector3 to something like a Master Script that does not get destroyed.
3 send quest progress to Master Script every time a progress is made.
4 LoadLevel 2.
5 Specify PC coordinates in that new level.
6 Load quest progress from Master Script upon loading the new scene.
7 [when leaving][in collision area] press "e".
8 LoadLevel 1, check for step 2 coordinates from Master Script, Rotate PC by 180 degree and place PC in that position.
9 Check for quest progress.
Also, how can I send stuff to Master Script, is it something like sendMessage.Master(...) and how can I call for specific data from that Master Script.
Answer by matcon · May 22, 2011 at 02:18 PM
Ok, I've figured it out! So here it is for all you other guys struggling with it!
Got to: GameObject > Create Empty. [You can rename that object, I'll name it Master.]
In your Project: Create > JavaScript. [Rename that script, I'll name it GameController.]
Edit GameController.js. [The script should look like this.]
function Awake()
/Activates this function when the script loaded. /
{ if(GameObject.Find("GameController")) { Destroy(gameObject); return; } }
gameObject.name="GameController";
/Changes the game objects name from Master to GameController. /
DontDestroyOnLoad(gameObject);
/Keeps Master/GameController alive all the time in all your scenes. It's the same object all the time. /
transform.position=Vector3.zero;
/Locates the Master/GameController object at x=0, y=0, z=0 on your new scene. Don't worry though, the object is invisible and has no colliders so you can't interact with it in game. /
transform.rotation=Quaternion.identity;
/ Sets the rotation of Master/GameController. Again, you can't see or touch it anyway in game. /
/------------------------------------------------------- /
public var enterInn = 0;
/ Set your variable to public so that it can be influenced through other scripts. The name enterInn can be anything, I use this name because I want to have this variable deal with the player entering an Inn in my game, its more like a reference in the code. And I set it to 0 so it doesn't trigger the "if" condition when the script is loaded. I want to change it to 1 from a script in other object. /
function Update()
/ Update means that this function will refresh every game frame. /
{ if(enterInn)
/ This "if" condition will be activated when enterInn = 1. It equals 0 until you change it to 1 in the other script. /
{
print("2");
/ Here you put all the stuff you want to be run/activated. I'll put a LoadLevel in here to load my Inn level and the coordinates of my player start location in that new level. It says print("2"); for now, it gives you a feedback in the console so you can see if it works or not. You will want to replace this print("2") with all the other stuff you want it to do. /
}
}
That's the first script. Now go to your Project > Drag GameController script to your Master object that's in your Hierarchy.
You should see in the Master objects Inspector that the script has been applied.
Now create other object that you will apply the second script to.
Create a new JavaScript in your Project.
Give it a name and edit it.
It should look like this:
var Master: GameController;
/ This will let you point the game object containin the GameController script, which is called Master in my example but you don't even need to give it the same name as your object containing that GameController script, its just a reference that will show in the Inspector. It can be named target as the Unity documentation says but if you would like to interact with more then one script it woll be a bit confuzing to name all of them "target". /
function Update()
/ It says Update in here, but you may want to trigger this function in a different way for example OnTriggerStay for colliders etc. If you leave it to Update it will look for a statement related to this function in the whole scene and all the time. / { if (Input.GetKeyDown("e"))
/ The Update will look for your input all the time and will loop constantly so every time you hit "e" on your keyboard this function will run whats inside that "if" statement. You can modify this to make your own conditions. /
{
Master.enterInn = 1;
/ So if the condition of "if" statement is met the function trigger the Master variable. The name Master in here should be the same as the name in the var Master:GameController above, the one that you used instead of "target" for your reference. It has nothing to do with the game object "Master". And then after "." you put the name of the variable in your GameController you want to manipulate, in this case it's the enterInn variable which will be changed to "1". This will result in your console printing a number "2". Because the variable enterInn in GameController is now set to "1" the GameController will run the "if(enterInn)" condition all the time until enterInn is "0" again. /
}
}
So that's how I did it hope it will work for you as well! Thanks to demize2010 and BigMisterB for your support!