Search Unity

NullReferenceException (Hear me out!)

Discussion in 'Scripting' started by DeathByRhino, Dec 2, 2015.

  1. DeathByRhino

    DeathByRhino

    Joined:
    Jul 30, 2015
    Posts:
    33
    I know there are plenty of null reference exception posts, but as far as I can tell none of them have the same issue as mine. I spent the past few days building a game stack for my game states, but I've hit a roadblock.

    I've tried to get a reference to the "Game" class which where the stack exists and changes states. This reference is in the gameManager variable, yet even though the inspector contains the appropriate component/script in the gameManager variable, it still pulls a null reference exception when initialized.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class MainMenuState : GameState
    5.     {
    6.     public string sceneID;
    7.     public GameState nextState;
    8.     public Game gameManager;
    9.     public OverworldState overworld;
    10.     void Awake()
    11.         {
    12.         gameManager = GetComponent<Game>();
    13.     }
    14.  
    15.     void Start()
    16.     {
    17.         nextState = new MainMenuState();
    18.         overworld = GetComponent<OverworldState>();
    19.         gameManager = GetComponent<Game>();
    20.         InitGame();
    21.     }
    22.  
    23.    public override void Update()
    24.     {
    25.  
    26.         if (Input.GetKey("a"))
    27.         {
    28.             Debug.Log("enter");
    29.             NewGame();
    30.         }
    31.     }
    32.    public void InitGame()
    33.   {
    34.         gameManager.pushState(nextState);
    35.         Debug.Log("Initgame");
    36.      
    37.     }
    38.     public void NewGame()
    39.     {
    40.         overworld = GetComponent<OverworldState>(); ;
    41.         Debug.Log("New Game");
    42.         Leaving();
    43.         gameManager.pushState(overworld);
    44.     }
    45.      public override void Entered()
    46.         {
    47.  
    48.         gameManager.loadLevel(0); //THIS IS WHERE THE ERROR APPEARS
    49.         }
    50.      
    51.      public override void Leaving()
    52.         {
    53.         Debug.Log("Main Menu leaving");
    54.      
    55.     }
    56.     }
    57.  
    58. I have noooo idea what to do!
     
    Last edited: Dec 2, 2015
  2. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    First you want to put up code tags. ;)

    Its pretty obvious that gameManager is null. Throw in a Debug.Log(gameManager) immediately before the line that is throwing the error to confirm this.

    gameManager is assigned in Start and Awake (why? just do it once in Awake) by calling GetComponent. GetComponent only returns null if the component is not on the same GameObject.

    Therefore I must assume that there is no Game script attached to the same GameObject that this script is attached to.
     
  3. DeathByRhino

    DeathByRhino

    Joined:
    Jul 30, 2015
    Posts:
    33
    upload_2015-12-1_19-55-52.png

    my bad about the code tags!

    Uhh the script is definitely attached to the game object, and when its playing the script even appears in the field. yet the function still returns null
     
  4. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    What is GameState? I'm really confused here because you've got Start and Awake methods, as if it's a MonoBehaviour. But you're saying "new MainMenuState" as if it's not. (You should never use new with a MonoBehaviour.)

    It's also weird that the MainMenuState is itself creating a new MainMenuState as the next state. How does that make sense?
     
    Kiwasi likes this.
  5. DeathByRhino

    DeathByRhino

    Joined:
    Jul 30, 2015
    Posts:
    33
    Game State is a abstract interface for my set of game states to enter in the Game State Stack

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. public abstract class GameState : MonoBehaviour
    5. {
    6.  
    7.     public virtual void Entered()
    8.     {
    9.  
    10.     }
    11.     public virtual void Leaving()
    12.     {
    13.  
    14.     }
    15.  
    16.     public virtual void Pause()
    17.     {
    18.  
    19.     }
    20.  
    21.     public virtual void Resume()
    22.     {
    23.  
    24.     }
    25.     public virtual void Update()
    26.     {
    27.  
    28.     }
    29.     public virtual void OnGUI()
    30.     {
    31.     }
    32. }
    33.  
    34.    And oh, I was unaware of the use of "new" with Monobehaviors!
     
    Last edited: Dec 2, 2015
  6. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    this isn't going to end well....
     
    JoeStrout and Kiwasi like this.
  7. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
  8. martinmr

    martinmr

    Joined:
    Mar 25, 2015
    Posts:
    325
    Have you checked if Start and Awake is even executed in MainMenuState script? . Because like your Screenshot shows in inspector none of your variables are set in MainMenuState Script.

    Try do add to your interface "GameState" a public virtual void Start and Awake und than public override void Start and Awake in your MainMenuState.
     
  9. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    There is an edit button to fix this. Fair enough if you missed it once. But after the error being pointed out to you?

    Happy now? ;)

    What does a Debug.Log immediately before the line throwing an error show? The first step of fixing a null reference error is always confirming exactly what is null. Go and do then come back and report.
     
  10. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    :p
     
    Kiwasi likes this.
  11. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    OK, yeah, you need to back up and reconsider your life (or at least your programming) choices.

    If a GameState is a MonoBehaviour, then yeah, you can't instantiate it with New. Not if you expect it to work properly, anyway.

    And you didn't answer my other question: why is your MainMenuState creating a new MainMenuState, and claiming that is the next state? How many MainMenuStates do you really need?

    Back up, describe in detail what it is you're trying to achieve, and how you are approaching it. Chances are good you will see where it's gone wrong yourself through this exercise. If not, we'll at least have a chance of helping you.

    And use code tags. :)
     
  12. DeathByRhino

    DeathByRhino

    Joined:
    Jul 30, 2015
    Posts:
    33
    Welp that took longer than it should have for some code tags

    And for the main menu state, I was trying to follow some online references to a game state stack, except that article wasn't using Unity or MonoBehaviors so I didn't take that into account (plus I'm a noob as you can see when I didn't know about the usage of new).

    Yeah writing a new Menu State was kind of just absentminded typing. the variable next state would have told the Game Manager that the Main Menu State was the next state to be pushed onto the stack.
    The Debug Log doesnt appear when I put it before the gameManager loadLevel line.
    My main problem may be that next state is null now I've taken out the new MainMenuState.
     
  13. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Let's back up. Why do you believe you need a "game state stack" at all? What is the problem you are trying to solve?

    (It's quite likely that there is an easier way to do it.)
     
  14. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    You don't even need a Log statement. You can tell by looking at the Inspector in the screen shot you provided that Game Manager is null.

    If it's exposed to the Inspector then why not just assign it there instead of via code?
     
  15. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    You might have a second instance of the MainMenuManager script somewhere in your scene. That other MainMenuManager would then throw the exception.

    Not an uncommon problem.
     
    Dantus likes this.
  16. DeathByRhino

    DeathByRhino

    Joined:
    Jul 30, 2015
    Posts:
    33
    Its more of keeping a cleaner Game State Machine so it doesnt bungle itself up later on while adding features. I'd rather struggle and learn Game Stack now than use enums and regret it later.

    Thats a negatory on that- though perhaps it was the "new MainMenuState()" line

    upload_2015-12-2_9-10-49.png ]
    this is the script running, and it has located and placed the script in the field, yet returns null at the gameManager.loadLevel();
     
  17. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Well, OK, but I've been using Unity for years and have produced a number of games, and I've never needed a Game State Stack. The overall state of the game (main menu, options, play, etc.) is neatly handled by simply putting them in different scenes. And within a game, well, there usually isn't all that much FSM in my games... it's more common to need a state machine on individual characters, which can be neatly handled with either the built-in Animator editor, or a bit of code, as illustrated in this article.

    Of course I've never used Play Maker either. And debugging this specific problem may be a useful exercise anyway.
     
    DeathByRhino likes this.
  18. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Did you consider script execution order? If the Entered method is executed before Awake or Start, the reference is going to be null, but will be initialized before the next frame.
     
  19. DeathByRhino

    DeathByRhino

    Joined:
    Jul 30, 2015
    Posts:
    33
    yeah because the function that calls Entered is last in Start.
     
  20. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    So wait - you said the log in Entered never showed up? And you were trying to instantiate with new? Is it possible that the exception is being thrown in your instantiated instance because Awake and Start are never called and not in the instance you have configured in your scene?
     
    Kiwasi likes this.
  21. DeathByRhino

    DeathByRhino

    Joined:
    Jul 30, 2015
    Posts:
    33
    Oh now I've gotten the logs in Enter appear when they are put before "gameManager.loadLevel();"
     
  22. DeathByRhino

    DeathByRhino

    Joined:
    Jul 30, 2015
    Posts:
    33
    Now that I took the "new MainMenuState()" out, it appears to be working properly, loading to the main menu scene and switching to gameplay once I hit the input key. There are still some niggles with the Game Stack, but that's an entirely different question.

    So in the end, it was caused by something I'm not even supposed to put in any Monobehaviors. Sorry for taking up your guys time like this -_-

    My biggest point of confusion was how to get a script to send a reference of itself (it sounds stupid, but hey).
     
    Last edited: Dec 2, 2015
    Kiwasi likes this.
  23. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Perhaps you're looking for this.
     
  24. DeathByRhino

    DeathByRhino

    Joined:
    Jul 30, 2015
    Posts:
    33
    I see what you did there