NullReferenceException Object reference not set to an instance of an object c# referencing function

Hi,

GetUpKidAK kindly suggested I should pass my values to another script for my game, and pass them back when the level is reset. Which is a very good idea. I have been trying to get it to work, but my lack of understanding for c# and coding in general is still holding me back :(.

Before I call Application.LoadLevel (“SideSpikeSlice”); to reset the level. I am trying to set the stats values from my object. To do this I have set up a class called PlayerStats.cs as well my my original class PlayerController.cs.

In PlayerController.cs I set the following:

private PlayerStats playerStats;

void Start () {
current = this;
playerPhysics = GetComponent ();
playerStats = GetComponent();
}

I call the function via:

playerStats.GetComponent().setStats();
Application.LoadLevel (“SideSpikeSlice”); //here is where the level resets

This is what the function being called looks like:

public void setStats(){

score = PlayerController.current.score;

}

I have also tried calling the function as PlayerStats.current.setStats(); as well as a variety of other ways people have explained it from google searches, none of them seem to work. I use the .current to get past the accessing non-static error that you receive if you don’t use is.

The PlayerController.cs script is attached to my player prefab, but my PlayerStats script is not attached to anything, as I just want it to store values. However, whenever I call the function it says:

NullReferenceException: Object reference not set to an instance of an object
PlayerController.Update () (at Assets/Scripts/PlayerController.cs:203), which is the line where I call the function to setStats();

I have the option to attatch sometihng to “Player Stats” in the inspector:
http://puu.sh/djEfU/8d73615276.png
But I can’t drag PlayerStats.cs in there :(.

I can’t attach the script to my player object, as when I reload the level it would then reload the script with the stats on it, as far as I understand. My player object does have a field for “Player Stats”, but I am unable to drag the PlayerStats script in there. I’m sure I’m being incredibly stupid, I just can’t seem to find an answer that works.

Cheers

Lucio

Please don’t forget to use code tags.

Since you said you never attach ‘PlayerStats’ to any GameObject and do not plan to do so, your call

playerStats = GetComponent<PlayerStats>();

is pointless. GetComponent can only return an instance of the script if it’s attached to the referenced GO that you’re calling the method from. In your case it always returns ‘null’.
Afterwards, when trying to access any member via ‘playerStats’ (the variable in your script) there will be the exception that occurs to you as it’s always ‘null’ and does not reference any object.

There are several quick solutions to your problem. Two of those are:

  1. Attach the script to a GO in order to get it from there
  2. Create a new object of your class with
playerStats = new PlayerStats(); // or any other constructor defined in your class

If you choose the latter, PlayerStats must not inherit from MonoBehaviour, you have to remove that.

Either way change

playerStats.GetComponent<PlayerStats>().setStats();

to

playerStats..setStats();

simply because it’s redundant.

As for your thought about the slot in the inspector:

When inheriting from MonoBehaviour (or more generally from UnityEngine.Object) and declaring a public variable, you’ll see a slot in the inspector. You can actually drag something in there: gameObjects with the appropiate script attached to it. The engine will then automatically get its component and assign it to your variable. If you decide to choose the first suggestion from above, you can use the slot in order to avoid getComponent in your script.

1 Like

Thank you for the explanation, it makes a lot more sense now, and actually works :wink:

Thanks again

Lucio

Hmm, I’ve run into a problem. I decided to go for the second strategy, by using a constructor. However, if I am assigning a new version of PlayerStats each time, does that not then reset PlayerStats.cs too, when PlayerController.cs restarts, as it requests a new version of it?

    void Start () {
        current = this;
        playerPhysics = GetComponent<PlayerPhysics> ();

        playerStats = new PlayerStats();
        Debug.Log ("Player stats score: "+playerStats.score);
        playerStats.getStats();
        Debug.Log ("Score after import:" + score);
     }

Here, my debug shows the score in PlayerStats.cs as the correct value, but in the code above, both before and after getStats(); is called, the value is 0. I tried setting the initialization value to 11, and the values are still 0, as if it is reading from a fresh copy of PlayerStats();

I don’t know whether I put the constructor in the wrong place, I probably did, but I can’t understand how it could work, if it keeps requesting a new version. (Calling getStats(); before the object is created creates another null exception ,which I understand is happening because the playerStats object hasn’t been created yet after the script reset.

Cheers

Lucio

Oh, my bad, I totally forgot about reloading the level when i wrote that.
You could solve the problem using statics, then you don’t even need to create an object. You could also go for singletons (if one ‘set’ of stats is enough) or some variation of it (if you need more more than one ‘set’ of stats).

As for the first solution, you’d use DontDestroyOnLoad and also something similar.

Third possibility: temporarily write the information to a file or player prefs and load it as soon as the level has finished loading.