x


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?

more ▼

asked Mar 08, 2010 at 09:17 PM

Oudaiesty gravatar image

Oudaiesty
215 24 25 32

(comments are locked)
10|3000 characters needed characters left

8 answers: sort voted first

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; }

more ▼

answered Mar 08, 2010 at 09:47 PM

duck gravatar image

duck ♦♦
47.8k 131 235 474

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.

Mar 08, 2010 at 09:57 PM Oudaiesty

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.

Mar 10, 2010 at 03:26 AM Oudaiesty

can you elaborate on the problems with 'mess' that you had?

Mar 10, 2010 at 08:22 AM duck ♦♦

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 instead I removed it from the game and made another object that will instantiate a new one if needed. This way instead 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.

Mar 10, 2010 at 05:21 PM Oudaiesty

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.

Mar 10, 2010 at 05:57 PM Oudaiesty
(comments are locked)
10|3000 characters needed characters left

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.

more ▼

answered Mar 11, 2010 at 08:17 PM

Cyclops gravatar image

Cyclops
8k 76 95 154

Avoid searching the scene by adding a static property to the manager class that returns the instance.

Sep 24, 2011 at 03:58 PM Rafes
(comments are locked)
10|3000 characters needed characters left

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.

more ▼

answered Nov 18, 2012 at 10:35 PM

MoHoe gravatar image

MoHoe
-4

(comments are locked)
10|3000 characters needed characters left

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() &lt; 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.

more ▼

answered Mar 10, 2010 at 08:26 PM

Oudaiesty gravatar image

Oudaiesty
215 24 25 32

(comments are locked)
10|3000 characters needed characters left

Hi,

I came up with this solution on a problem of RELOADIN SAME level and still wanted to retain data.

It is quite simple. You will have empty level (scene) with only one Game Object and script attached to it. This will be our special level. Let’s call this level LEVEL0.

Make this object indestructible with DontDestroyOnLoad(), called from Awake() function. Put all global variables in this script, with or without static prefix – your choice. After DontDestroyOnLoad() - load LEVEL1, which is your game level or menu level.

Any time you want to reload LEVEL1, you can. All data will be there and since you are not loading LEVEL0, your GameObject will not multiply.

In this way you can make as much levels as you want. Just make those levels after our special LEVEL0, and never load LEVEL0 again.

Regards.

more ▼

answered Nov 02, 2011 at 04:10 AM

Mox gravatar image

Mox
295 1 3 8

This method doesn't allow you to play a level directly in the Unitor Editor as you always have to start by playing the boot level 0. :-( Supposedly you would have to access the persisted object with GameObject.Find(name) as you are not able to pass this object as a param to scripts that want to use it.

Mar 08 at 04:49 PM bjbrewster
(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x1206
x679
x411
x168
x9

asked: Mar 08, 2010 at 09:17 PM

Seen: 23891 times

Last Updated: Mar 09 at 01:56 AM