very strange NullReferenceException

OK - I’ve been following the Stealth game project example - didn’t really like the way the guy’s been organizing the code - so I thought I could do better - so basically, what I have is:

1- a game object called ‘gameController’ (much like in the tuts) that has:
A) a script attached to it called “GameControllerScript”
B) a number of child objects (you don’t have to know about all of them) - one of them is “music”

2- now ‘music’ has:
A) a script attached to it called “MusicScript”
B) two child objects: NormalMusic, PanicMusic each with NormalMusicScript and PanicMusicScript attached to respectively.

Logically, I made NormalMusicScript and PanicMusicScript inherit from MusicScript, here’s my codes:

public class Music : MonoBehaviour {

	public float maxVolume = .8f;
	public float minVolume = .1f;
	public float fadeSpeed = 2f;
	protected GameControllerScript gameController;
	protected float targetVolume;

	public virtual void Awake()
	{
		gameController = transform.parent.gameObject.GetComponent<GameControllerScript>();
	}
	public void FadeTo(float volume)
	{
		audio.volume = Mathf.Lerp(audio.volume, volume, fadeSpeed * Time.deltaTime);
	}
}
public class PanicMusicScript : Music {

	void Update()
	{
		if (gameController.PlayerHasBeenSpotted())
		{
			targetVolume = maxVolume;
		}
 		else
		{
			targetVolume = 0;
		}
		FadeTo(targetVolume);
	}
}

(The NormalMusicScript has similar code so no need to post it)

Now the problem is: when I run the game, I get a NullReferenceException at the line

 if (gameController.PlayerHasBeenSpotted())

saying that gameController is null - So I debugged to check the problem - I put a breakpoint at the assignment of gameController in the Awake of MusicScript parent class - it got assigned no problem - but then after I stepped, the same Awake of the parent got executed again! - but this time, gameController returned null! - I didn’t know what that was about - so I thought that if I didn’t override the Awake in the child, the Awake of the parent will also get called on the child - so I tried this:

public override void Awake()
{
    return;
}

When I debugged again - it didn’t execute Awake twice - but still broke at the same line saying that gameController is null :frowning:
I tried to use the constructor instead of Awake (cuz I remember having similar problem in the past and managed to solve it that way) but no luck - got some other errors saying not to use the constructor or something…

Why is this happening? - any help would be appreciated - thanks a lot in advance.

I would assume that components are being loaded in order. It may not be an order that you expect? Do you have any particular reason not to put gameController initialization in Start instead of Awake?

Nope - that didn’t change anything - I used Start instead of Awake - Now the Start of MusicScript got executed more than once - I didn’t override it in the children - so I think this is clearly an issue with inheritance.

It’s an issue with the way you have the GameObjects organized. The Awake is being called twice because two scripts of type Music are attached to a GameObject. The problem is that they are in different spots in the hierarchy so transform.parent returns something different each time.

what do you exactly mean with

  • I didn’t quite get you there - I’m pretty much sure I got only one MusicScript script attached to the ‘music’ GameObject.

What do you suggest a better way of organizing my game objects in an OOP fashion such that I could use inheritance?

I never had this issue, but i reckon i know what is causing it! You need to override Awake and call it on the base, like so:

public class PanicMusicScript : Music {

 public override void Awake(){
    base.Awake(); 
  }

//Rest of code here

Nope ^^ - That ‘invokes’ the issue calling the base Awake another, 3rd time? - I tried it - same.

Not possible, unless you have your parent class on a GameObject as well, which will cause all kinds of strange things. Inheritance is about having a base class with common features, then your derived classes get attached to GameObjects. If you attach the parent, then all kinds of weird things can happen.

Just tested it my end, no problems, works fine and does what it is suppose to do.

The base class (parent) simply has common variables, methods, etc. So your’s is fine. Now for every class that derives from it, that should be the one attached to a GameObject, not the base class.

So

Music (GameObject) < no Script!
-PanicMusic (GameObject) < place panic script
etc.

Awake will get called on the base class for every derived class that uses it.

OK - Wait just a second

Well, yes, I do have the MusicScript (which is the parent class) - attached to the parent gameObject of NormalMusic and PanicMusic (which is ‘music’)
But, isn’t that how it’s supposed to be done? - I mean, if I don’t do that, then who am I going to make gameController common between all inheriting classes? - because if I don’t attach MusicScript to the ‘music’ gameObject, gameController obviously isn’t gonna be the parent of ‘music’ - so I can’t do transform.parent inside MusicScript - I just tried assigning gameController via tags like so: gameController = GameObject.FindWithTag(“GameController”).GetComponent(); - But I’m also having the same issue :frowning:

here’s what I have so far:

public class Music : MonoBehaviour {

        // some stuff....

	public virtual void Awake()
	{
		gameController = GameObject.FindWithTag("GameController").GetComponent<GameControllerScript>();
	}
        // other stuff...
}

public class NormalMusicScript : Music
{
	public override void Awake()
	{
		return;
	}
        // stuff...
}

Also, I did exactly as you told me - I didn’t attach the MusicScript to the ‘music’ gameObject - Although I thought that if you don’t attach a script, you won’t be able to use it.

Oh OK - sorry - last comment was kinda useless - I tried base.Awake() and it worked - thanks very much! - but could you answer my last questions on my previous comment? - why does it cause trouble if you attach the parent script to the music object? - how can you use a script, if you didn’t attach it to anything - still in your hierarchy?

This is exactly what I meant when I said you had an issue with how the GameObjects were organized. There’s no real need to do this.

Well, the base class is derived from Monobehaviour, your derived classes derive from your base. The only thing that wont work in the base class is things like StartCoroutine, etc unless it is attached to a GameObject. I mean there is no reason why you can’t attach the base class to a GameObject, but you will need to ensure that it don’t cause issues.

One last thing, why do I feel as if Unity is telling us not to use inheritance and OOP? :frowning: what’s the better approach then? - I’m confused.
In a scenario like mine, isn’t inheritance the way to go?

I think there is somehow a confusion here. You seem to have an impression that parent/child relationship of the GameObject translates or needs to translate to the C# object inheritance. I don’t think that is the case. If you are trying to have something accessible from the parent GameObject to all children (to be shared by children) then my suggestion is treat is as a sharable resource. In other words:

  1. Just make this shared resource a property of the Monobehaviour attached to parent (that Monobehaviour should not be a base class for scripts attached to the GameObject children).
  2. Create a base Monobehaviour class that knows how to get the shared resource from a parent.
  3. Derive 2 classes from this base and attach each to appropriate children. The result would be exactly what you are trying to achieve.