- Home /
How to keep certain information when reloading a level
I'm trying do decide which way would be better to reset a match and return everything to its normal positions so that they can be replayed from the default spots.
The options I came up with were: -Reset all the locations manually using code to save the locations to reset to.
or
-Reset all the locations by just recalling the "Application.LoadLevel("Scene")
I want to do this while keeping in mind that there are variables and game objects that I want to keep or destroy such as the score, the number of players and their names and other specifics.
the second option seems much easier, but the problem is deciding which game objects I want to save such that the variables I want to keep are preserved.
I have a individual player status, a level status, and the status of the targets which are being struck(which disappear when hit)
If I were to use the DoNotDestroyOnLoad(this) what are the specifics that are applied to it? does it only cover Game Objects or can I get more precise and pick and choose variables to save for the next round? if not whats a good set up that possible?
Answer by duck · Mar 08, 2010 at 09:47 PM
The DontDestroyOnLoad function is generally used to preserve an entire GameObject, including the components attached to it, and any child objects it has in the hierarchy.
You can't specify individual variables to preserve, but if you want to minimise the amount of data preserved, you could create an empty GameObject, and place only the script containing the variables you want preserved on it.
Then, when you place this line in your script's Awake() function,
DontDestroyOnLoad (this);
it will cause just this empty GameObject and the attached script to persist through the load.
That said, it's also relatively easy to have a script on each object which stores the original position and rotation values of each object, and has a "Reset" function which sets the current position and rotation back to the original values (and perhaps zeroes the velocity and angularVelocity values too).
It would look something like this:
var originalPosition : Vector3; var originalRotation : Quaternion;
function Start() { originalPosition = transform.position; originalRotation = transform.rotation; }
function Reset() { transform.position = originalPosition; transform.rotation = originalRotation; }
Excellent excellent! I really appreciate this. I'm going to give that a shot now it looks quite solid. So I shouldn't have any problems.
Ugh I had some issues with the don't destroy on load, it just makes a huge mess and and to account for it i'd have to code a little too much more than necessary. I'm going to try option 2 next.
can you elaborate on the problems with 'mess' that you had?
Well after I did some more testing on it I found that it created a new game object of the same type rendering the previous one useless. But I later found that if I did a check to see if the "dataHolder" object existed then don't make a new one. It kept making more because it was already in the hierarchy from the beginning. So ins$$anonymous$$d I removed it from the game and made another object that will instantiate a new one if needed. This way ins$$anonymous$$d of it making multiple copies of the same object it discerns if it needs to make one via instantiation. I think that might solve a problem or two.
I would like to add that the first option is looking pleasing again. I just went about it in a really awkward fashion. I'm going to give it a shot and this post it here just in case you want to improve on it or if anyone else finds it useful.
Answer by Cyclops · Mar 11, 2010 at 08:17 PM
This is a good question. I've been thinking about both it and another post talking about having a LevelManager object, which can manage data between level/scene changes. Plus the problem of how to make an object into a Singleton, so you don't get multiple copies.
Here is my attempt at solving the problem. First, I posted a package with all the code on the forums at: Simple Demo of a LevelManager.
I will admit, like a lot of people, I don't like Singletons... :( But you do need some way to prevent duplicate objects. My solution involves two C# scripts (s_bootstrap and s_LevelManager), and two GameObjects (Bootstrap and LevelManager, which is turned into a Prefab).
I create two empty Gameobjects, Bootstrap and LevelManager. On LevelManager, I attach the script s_LevelManager. Then I make LevelManager into a Prefab, and delete it from the Hierarchy. This way it won't be created automatically when the level starts, so no duplicates.
On Bootstrap, I attach the script s_bootstrap, and set a Prefab variable to the LevelManager Prefab object. Bootstrap should be on the first scene/level to load.
This is the sequence of events when execution starts: The first scene loads, creates a Bootstrap GameObject. Bootstrap check for a LevelManager object, and if none - creates one, makes it immortal with DontDestroyOnLoad(). Then Bootstrap suicides :) it does Destroy() on itself, removing it from the Hierarchy. So the next time the scene is loaded, Bootstrap will not be created. Leaving an un-attached LevelManager floating somewhere in cyberspace.
Then, any object that wanted to reference the LevelManager GameObject could find it by name, get a reference the s_LevelManager script, and could call the public functions on that script:
GameObject tmp = GameObject.Find("LevelManager");
if (tmp != null) {
s_LevelManager slm = tmp.GetComponent<s_LevelManager>();
String curLevel = Application.loadedLevelName;
int count = slm.getTimes();
msg.text = curLevel + ", changes = " + count;
slm.bumpTimes();
}
I decided not to include the code for s_bootstrap/s_LevelManager, keep things from getting too long :) But again, if you do want the code, it's at: Simple Demo of a LevelManager.
Avoid searching the scene by adding a static property to the manager class that returns the instance.
Answer by DanielJF · Nov 20, 2013 at 09:22 AM
You can also try to look into PlayerPrefs i will give you a link to unity api for you.
http://docs.unity3d.com/Documentation/ScriptReference/PlayerPrefs.html
public float myFloat;
void RememberMe ()
{
PlayerPrefs.SetFloat("MyValue",myFloat);
PlayerPrefs.GetFloat("MyValue");
}
Thank you so much!! This fixed the problem I was struggling with for hours!!
Answer by user1j3di3j2sa3 · Nov 18, 2012 at 10:35 PM
DoNotDestroyOnLoad sucks big time. I don't understand unity's logic here. it's supposed to keep the object and vars into the next scene, but all it really does is instantiates it, so why bother adding this feature when I can just simply instantiate it?
for the first time I've felt unity is a waste of money. I wish I had tested it first, at least now i know why unity isn't used in big projects.
Yes you can use all the data storage methods but how tedious and counter intuitive that is, not to mention the time it would take to build a complex game.
Just because unity team didn't do the right thing in this little area means that big projects will take years to finish.
Answer by Oudaiesty · Mar 10, 2010 at 08:26 PM
Well after applying what was said about DontDestroyOnLoad I came up with this.
It took me a while to figure it out but heres what I have so far.
// This object will presist and will delete itself if there was already a previous object preventing collisions var dSetNumber : int = 0; var dFramePoints : int = 0; var dStrikeCount : int = 0; var dTotalStrikes : int = 0; var dIsStrike : boolean = false; var dIsSpare : boolean = false;
var pins : PinStatus[]; var pChar : Status; private var gameLink : LevelState; private var dataManager : PlayerDataManager; // Not being used function Awake() {
collisions = FindObjectsOfType (DataState); for (var collision : DataState in collisions) //This method seems to work just fine I'm not sure why. {
if(transform.GetInstanceID() < collision.GetInstanceID())
Destroy(gameObject);
}
DontDestroyOnLoad(this); //if((transform.name == "PlayerData " + GetInstanceID()) == GameObject.Find("PlayerData 10916")) // Destroy(gameObject);
gameLink = FindObjectOfType(LevelState); if(!LevelState) { Debug.Log("LevelState.js does not exist"); }
} function GetLatestSet() : int {
return dSetNumber;
}
function StoreGame() {
dSetNumber = gameLink.setNumber;
dFramePoints = 10 - gameLink.numberOfPins;
}
function SavePlayer() { //dStrikeCount = pChar.strikeCount; //dIsStrike = pChar.isStrike; //disSpare = pChar.isSpare; //dTotalStrikes = pChar.totalStrikes;
}
That solves the keeping the data part now I have to actually send the data back to the game when it gets reloaded. look good? EDIT This doesn't work too well either.