Search Unity

Application.LoadLevel() question

Discussion in 'Scripting' started by Reizla, Apr 17, 2015.

  1. Reizla

    Reizla

    Joined:
    Nov 5, 2013
    Posts:
    136
    When reading the description for Application.LoadLevel() it states that "When loading a new level all game objects that have been loaded before are destroyed." Pretty straightforward I thought, but not as much as I wanted (or thought). With my current game I hope from actual level to actual level using this method. I figured that it would also destroy all data in the game but it does not. When progressing through the game the levels get messed up with the old data that appear in memory.

    Is this the right behavor of the function? i.e. data I store in memory are no game objects?
     
  2. ensiferum888

    ensiferum888

    Joined:
    May 11, 2013
    Posts:
    317
    The only reason some data would remain after LoadLevel() is if it lives in a static class that's not on a GameObject, or on a Monobehaviour on a GameObject that was set with DontDestroyOnLoad(gameObject).

    I actually ran into this problem recently so what I did was create an empty scene and load that instead of reloading my original level. I was able to see that my LevelManager object was not getting destroyed. Try it and see if anything appears in the empty scene.
     
    blizzy likes this.
  3. Reizla

    Reizla

    Joined:
    Nov 5, 2013
    Posts:
    136
    None of these is the in my game. The game has 3 scenes: Menus, Movies (still work in progress, completely empty aside from a textmesh stating it's movies and waiting for a key to be pressed) & MainGame. In MainGame, I'm loading the level data though a game that's linked on an empty GameObject. This one runs fine. When the level is over (either game over, level exit or completed) it checks if if should go back to Menus, load Movies or reload MainGame. If it's the last then I agree that it could happen that data might 'hang' in memory. But the cases that I had my 'hanging' data was when I went out of the level and back to Menus, from there I selected to play the next level and Movies was loaded and then MainGame. No way there should be any data 'hanging' anywhere in this case...

    Luckily my issue isn't overly big either. As said, all that's 'hanging' are the data of the level, which is just an array of roughly 25x25. It's pretty easy to clear it by calling a small routine, which I have done already...
     
  4. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Where does your 25x25 array of data live?
     
  5. Reizla

    Reizla

    Joined:
    Nov 5, 2013
    Posts:
    136
    Only in the MainGame's main procedure. I'm calling it from other procedures within MainGame, but that should not affect the 'hanging' in memory.
     
  6. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    I have no idea what this means. Scenes don't have "procedures".
     
  7. Reizla

    Reizla

    Joined:
    Nov 5, 2013
    Posts:
    136
    ...old school Pascal programmer here... With 'Procedure' I mean script ;-)
     
  8. Reizla

    Reizla

    Joined:
    Nov 5, 2013
    Posts:
    136
    Just found out that aside from the old level, also lists are kept in memory. This is real odd and I'm starting to wonder if this is not some sort of bug (still using Unity 4.6.3.f1)? I also tried to add an OnApplicationQuit() method/event to the MainGame, but that's not working either. This means that at this moment I have to clear my levels completely before even starting to build a new one (which is freshly called when starting MainGame).
     
  9. ensiferum888

    ensiferum888

    Joined:
    May 11, 2013
    Posts:
    317
    OnApplicationQuit() will not work in the editor. I think we're confusing scripts, objects and scenes here. At first you stated that MainGame was a scene and now you say it's a script.

    I think we would need to see a bit of code in order to better assist you. For example your MainGame script and your level loading code.
     
  10. Reizla

    Reizla

    Joined:
    Nov 5, 2013
    Posts:
    136
    OnApplicationQuit() is not working between scenes either. I have given it a try in a compiled EXE but yet the list stays in memory between the scenes :(

    MainGame is a scene and there's an object with a linked script attached to it called MainGameHandler (my bad in the previous message). To the MainGameHandler I have added that OnApplicationQuit() when exiting to an other scene and that's not working.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6.  
    7. using PlayerPrefs = PreviewLabs.PlayerPrefs;
    8.  
    9. public class myBubbleList:IEquatable<myBubbleList>
    10. {
    11.    public int myFoundX { get; set; }
    12.    public int myFoundY { get; set; }
    13.    public int myColor { get; set; }
    14.  
    15.    public myBubbleList(int myX, int myY, int myC)
    16.    {
    17.      myFoundX=myX;
    18.      myFoundY=myY;
    19.      myColor=myC;
    20.    }
    21.  
    22.    public override bool Equals(object obj)
    23.    {
    24.      if (obj==null) return false;
    25.      myBubbleList objAsPart = obj as myBubbleList;
    26.      if (objAsPart==null) return false;
    27.      else return Equals (objAsPart);
    28.    }
    29.    public override int GetHashCode()
    30.    {
    31.      return myFoundX;
    32.    }
    33.    public bool Equals(myBubbleList other)
    34.    {
    35.      if(other==null) return false;
    36.      return (this.myFoundX.Equals(other.myFoundX) && this.myFoundY.Equals(other.myFoundY)); // Return both X amd Y coordinates
    37.    }
    38.  
    39.    public int CompareTo(myBubbleList other)
    40.    {
    41.      if(other==null)
    42.      {
    43.        return 1;
    44.      }
    45.      return myFoundX - other.myFoundX;
    46.    }
    47. }
    48.  
    49. public class MainGameHandler : MonoBehaviour
    50. {
    51.  
    52.    // List of possible Bubbles to clear
    53.    List<myBubbleList> MyBubbleList = new List<myBubbleList>();
    54.    static private List<myBubbleList> specialBubbleList = new List<myBubbleList>();
    55.    static public List<myBubbleList> SpecialBubbleList
    56.    {
    57.      get
    58.      {
    59.        return specialBubbleList;
    60.      }
    61.      set
    62.      {
    63.        specialBubbleList=value;
    64.      }
    65.    }
    66.  
    67.    // Initialize the game
    68.    void Awake()
    69.    {
    70.      // Get the ACTUAL screen resolution
    71.      MyScreenWidth=(float)Screen.width;
    72.      MyScreenHeight=(float)Screen.height;
    73.  
    74.      // Initialize the current level
    75.      PlayerPrefs.EnableEncryption(true); // Use encryption for PlayerPrefs()
    76.      #if UNITY_EDITOR
    77.      PlayerPrefs.EnableEncryption(false); // DO NOT use encryption for PlayerPrefs() in the editor!!!
    78.      #endif
    79.      MyLevel=PlayerPrefs.GetInt("Level");
    80.      MyDifficulty=PlayerPrefs.GetInt("Difficulty");
    81.      ScoreText.MyScore=PlayerPrefs.GetInt("Score");
    82.  
    83.      #if UNITY_ANDROID
    84.      Screen.sleepTimeout = (int)SleepTimeout.NeverSleep;
    85.      #endif
    86.      Application.runInBackground = true;
    87.  
    88.      GamePaused=false;
    89.      GameOver=false;
    90.      gameOverMsg=false;
    91.      LevelHandler.CreateLevel();
    92.    }
    93.  
    94.    // Use this for initialization
    95.    void Start ()
    96.    {
    97.      CreateBubbleGrid();
    98.    }
    99.  
    100.    // Update is called once per frame
    101.    void Update ()
    102.    {
    103.      if(!GamePaused)
    104.      {
    105.        if(Input.GetKeyDown (KeyCode.Space) && !GameOver)
    106.        {
    107.          GamePaused=true;
    108.        }
    109.        if(GameOver)
    110.        {
    111.          EndOfLevel();
    112.        }
    113.      }
    114.      else
    115.      {
    116.        if(Input.GetKeyDown (KeyCode.Space))
    117.        {
    118.          GamePaused=false;
    119.        }
    120.      }
    121.      if(Input.GetKeyDown (KeyCode.Escape) && !GameOver)
    122.      {
    123.        if(!GamePaused)
    124.        {
    125.          // Change into YES / NO selection later on
    126.          Application.LoadLevel ("StartMenu"); // EXIT to main menu
    127.        }
    128.        else
    129.        {
    130.          GamePaused=false;
    131.        }
    132.      }
    133.    }
    134.  
    135.    void EndOfLevel()
    136.    {
    137.      if(Input.GetKeyDown(KeyCode.Escape))
    138.      {
    139.  
    140.        // Game Over - Figure out WHY it happened
    141.        if (MyTimeLeft<=0)
    142.        {
    143.          // Out of time
    144.          Application.LoadLevel("StartMenu");
    145.        }
    146.        if (MyColor2Kill<=0)
    147.        {
    148.          // Level completed
    149.          PlayerPrefs.SetInt("Score",ScoreText.MyScore);
    150.          MyLevel++;
    151.          PlayerPrefs.SetInt("Level",MyLevel);
    152.          PlayerPrefs.SetInt("MaxLevel",MyLevel);
    153.          PlayerPrefs.Flush ();
    154.        
    155.          if(LevelData.LevelMovie(MyLevel)) Application.LoadLevel("Movies");
    156.          else Application.LoadLevel("MainGame");
    157.        }
    158.      }
    159.    }
    160. }
    Quite a lot there and I removed all things not really necessary. The CreateBubbleGrid() method in Start() is only created the actual level. The LevelHandler.CreateLevel() actually builds up the data to be used in CreateBubbleGrid() and creates a small list stored in SpecialBubbleList which is pretty straight forward:

    Code (csharp):
    1.      MainGameHandler.SpecialBubbleList.Add(new myBubbleList(9,14,32));
    2.      MainGameHandler.SpecialBubbleList.Add(new myBubbleList(10,14,32));
    3.      MainGameHandler.SpecialBubbleList.Add(new myBubbleList(8,16,32));
    4.      MainGameHandler.SpecialBubbleList.Add(new myBubbleList(11,16,32));
    5.      MainGameHandler.SpecialBubbleList.Add(new myBubbleList(9,18,32));
    6.      MainGameHandler.SpecialBubbleList.Add(new myBubbleList(10,18,32));
     
  11. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    SpecialBubbleList is static That's why it isn't cleaned up.

    OnApplicationQuit is called when the program is exited - not between level loads. You'll want OnLevelWasLoaded for that.
     
  12. Reizla

    Reizla

    Joined:
    Nov 5, 2013
    Posts:
    136
    Hmm... That's a problem. I need to make it static for other scripts to call and use it (like LevelHandler.CreateLevel()). Means I have to clean up all the static variables (including the list) at the load of the scene before initializing the whole thing again.

    I'll keep that one in mind for other (non static) things in the future. Thanks!
     
  13. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Not necessarily - the other scripts just need to find the instance of MainGameHandler.
     
  14. blizzy

    blizzy

    Joined:
    Apr 27, 2014
    Posts:
    775
    Perhaps you should come up with a wrapper class to reduce the number of static variables. That way you only need to create a new instance to get rid of all the old stuff.
     
  15. Reizla

    Reizla

    Joined:
    Nov 5, 2013
    Posts:
    136
    I don't get it. Well, I do get the 2 above comments about the static LIST being held in memory and I should make an instance of MainGameHandler. But the below variable is static as well and NOT held in memory between scenes:
    Code (csharp):
    1.   // Number of KEYs owned
    2.    static private int myOwnedKeys;
    3.    static public int MyOwnedKeys
    4.    {
    5.      get
    6.      {
    7.        return myOwnedKeys;
    8.      }
    9.      set
    10.      {
    11.        myOwnedKeys=value;
    12.      }
    13.    }
    It should be held in memory as well because it's a static one but yet it is not held. And I made sure I didn't yet clean it up when starting MainGameHandler...
     
  16. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    "Held in memory" is sort of a misnomer here because this example uses a primitive type. An integer *always* has some value associated with it (0 by default). Your previous example was a reference type (List) containing, essentially, pointers to other reference types. Managed reference types are only garbage collected when explicitly set to null or when nothing is referencing them anymore. Your static list is always keeping a reference to them so they're never GC'd.

    To further complicate this example - properties backed by primitive types return a copy of the backing field, not the backing field itself.

    Now if you're saying you set that property to some value other than 0 and loading a new level causes the value to be changed back to 0 then that's something I'd not have expected to happen.
     
    Last edited: Apr 24, 2015