Null Reference Exception

Getting a Null Reference Exception every time this is called from the Player Movement script (Or rather when the delegate notifies it):

	// Notify delegates of highest priority game object under mouse when clicked
	if (Input.GetMouseButton (0))
	{
		notifyMouseClickObservers (priorityHit.Value, layerHit);
	}

Note that the print(“click!”); command within the method ProcessMouseClick(…) is not being called, I suppose because there is no raycasthit or layerhit being passed.

Any ideas?

I’m getting the same error. Don’t know what to do with it tho…

getting the same error. it showed up in one of the earlier lectures where he was getting a null ref and he never showed us how he fixed it.

i’m about to tear my hair out over here. i’ve checked everything, the values being passed in are not null, the function that i added to the delegate list has the proper signature and everything

NullReferenceException: Object reference not set to an instance of an object
CameraRaycaster.LateUpdate () (at Assets/Camera & UI/CameraRaycaster.cs:49)

// Notify delegates of highest priority game object under mouse when clicked
	if (Input.GetMouseButton (0))
	{
		notifyMouseClickObservers (priorityHit.Value, layerHit);
    }

I’ve been scratching my head over this for days. Has anyone found a solution?

It’s typically a bad idea to call the delegate without checking first that it isn’t null, e.g. whether it has any subscribers.

The steps I would take here to diagnose the problem would be as follows;

  • comment out your line of code within the if statement
  • use Debog.Log in two separate statements to output priorityHit.value and layerHit

Assuming you see values other than null when you do this you can rule those out.

At this point I would then wrap the delegate call in a validation check;

if (Input.GetMouseButton (0))
{
    if(notifyMouseClickObservers)
    {
        notifyMouseClickObservers(priorityHit.Value, layerHit);
    } 
}

Let us know how you get on.

1 Like

Thanks for such a speedy reply, Rob.

I tried the techniques you recommended and found both priorityHit.Value and layerHit did NOT return null. My delegate was indeed null.

I checked again that I was properly subscribed in PlayerMovement.Start with the following line of code:

cameraRaycaster.notifyMouseClickObservers += ProcessMouseClick;

(head scratching begins again …)

On a whim, I moved that whole block of code to PlayerMovement.Awake and that fixed the problem for me.

Now I need to figure out how CameraRaycaster.Update ran before PlayerMovement.Start.

I might add that I’m using Unity 2018.2

Hi,

You are more than welcome.

Your issue is going to be the order of events. Before you made your change, a call was being made to your delegate before the subscribers had subscribed. Whilst all of the Start methods are called before say, Update, you cannot guarantee that they will be executed in your preferred order unless you implement the Script Execution Order and effectively weight them. Where-ever possible I would avoid using the Script Execution Order as it provides a fantastic way of hiding what is going on.

You could also consider the OnEnable and OnDisable methods for use with delegates, as really you should be unsubscribing from them too. :slight_smile:

Because the Awake method is called before Start, this is why after you made your change your code doesn’t error, as all of the subscribers are no in place before a call is made to the delegate.

Hope this helps :slight_smile:


See also;

1 Like

Once again, big thanks. Now I can get back to the course. The references you listed are sure to be most helpful.

1 Like

You are more than welcome :slight_smile:

1 Like

I am confused as to what “whole block” of code you moved to Awake to fix this issue.

I moved:

cameraRaycaster = Camera.main.GetComponent<CameraRaycaster>();
cameraRaycaster.notifyMouseClickObservers += ProcessMouseClick;

to the Awake method but I still get a nullReference exception.

I don’t understand why the teacher’s code works, but my identical code does not.

I tried to place the if statement: if(notifyMouseClickObservers)

inside the if (Input.GetMouseButton (0)), but I get an error saying that “notifyMouseClickObservers” is not a bool type.

Hi,

to the Awake method but I still get a nullReference exception.

Perhaps post your script(s) and indicate the specific line number of the error.

I tried to place the if statement: if(notifyMouseClickObservers)

inside the if (Input.GetMouseButton (0)), but I get an error saying that “notifyMouseClickObservers” is not a bool type.

It isn’t, but what you can do is an evaluation, e.g.

if(notifyMouseClickObservers != null)
{
    // do stuff
}

Hope this helps :slight_smile:

Uhm, it is interesting. When I click on the ground the ProcessMouseClick called 6 times each click.

Okay! I unstained what you meant now, sorry. I must have missed the “!” before the = sign.

I tried fixing the problem for 2 hours but to no avail…

I am still getting null references at:

if (Input.GetMouseButton (0))
{
      notifyMouseClickObservers(priorityHit.Value, layerHit);
}

When I used Debug.Log for the outputs of priorityHit.value and layerHit within the != null statement, I never got any logs in the console. So I Only have null.

My PlayerMovement script is as follows:

using System;
using UnityEngine;
using UnityStandardAssets.Characters.ThirdPerson;
using UnityEngine.AI;

[RequireComponent(typeof (NavMeshAgent))]
[RequireComponent(typeof (AICharacterControl))]
[RequireComponent(typeof (ThirdPersonCharacter))] 
public class PlayerMovement : MonoBehaviour {

    AICharacterControl aiCharacterControl = null;
    ThirdPersonCharacter thirdPersonCharacter = null;  
    CameraRaycaster cameraRaycaster = null;
    Vector3 currentDestination;  

    private bool isInDirectMode = false;  

	void Start()
    {
        cameraRaycaster = Camera.main.GetComponent<CameraRaycaster>();
        thirdPersonCharacter = GetComponent<ThirdPersonCharacter>();
        currentDestination = transform.position;  
        aiCharacterControl = GetComponent<AICharacterControl>();
        cameraRaycaster.notifyMouseClickObservers += ProcessMouseClick; 
    }

    void ProcessMouseClick(RaycastHit raycastHit, int layerHit)
    {
        print("Click");
    }

    //TODO Make this get called again
    void ProcessDirectMovement()
    {
        Debug.Log("In direct movement mode");
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        // calculate camera relative direction to move:
        // calculate move direction to pass to character
        Vector3 cameraForward = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized;
        Vector3 movement = v * cameraForward + h * Camera.main.transform.right;
     
        thirdPersonCharacter.Move(movement, false, false);
    }
}

Should I post my CameraRaycaster or CursorAffordance script as well?

Hi,

cameraRaycaster = Camera.main.GetComponent<CameraRaycaster>();
cameraRaycaster.notifyMouseClickObservers += ProcessMouseClick;

Put the above lines of code into the Awake method instead of Start and re-run.

private void Awake()
{
    cameraRaycaster = Camera.main.GetComponent<CameraRaycaster>();
    cameraRaycaster.notifyMouseClickObservers += ProcessMouseClick; 
}

Let me know how you get on :slight_smile:


See also;

Moved it. Unfortunately I still get:

NullReferenceException: Object reference not set to an instance of an object
CameraRaycaster.Update () (at Assets/Camera and UI/CameraRaycaster.cs:81)

Can you post those scripts also please :slight_smile:

If that refers to this bit of code;

if (Input.GetMouseButton (0))
{
      notifyMouseClickObservers(priorityHit.Value, layerHit);
}

The delegate should really be being checked for null before being used, e.g. no subscribers are present, like this;

if (Input.GetMouseButton (0))
{
    if(notifyMouseClickObservers != null)
    {
        notifyMouseClickObservers(priorityHit.Value, layerHit);
    }
}

I have the code checked for if it is null.
(Sorry for the bad formatting, I will correct that)

Code for my ProcessMovement:

[RequireComponent(typeof (NavMeshAgent))]
[RequireComponent(typeof (AICharacterControl))]
[RequireComponent(typeof (ThirdPersonCharacter))]  
public class PlayerMovement : MonoBehaviour {

    AICharacterControl aiCharacterControl = null;
    ThirdPersonCharacter thirdPersonCharacter = null;   // A reference to the ThirdPersonCharacter on the object
    CameraRaycaster cameraRaycaster = null;
    Vector3 currentDestination;  // required so we don't start moving in some arbitray direction or start moving, until we actually click.

    private bool isInDirectMode = false;  //TODO Consider making static later if other scripts 
										  //require this information.   

	void Awake()
	{
		cameraRaycaster = Camera.main.GetComponent<CameraRaycaster>();
        cameraRaycaster.notifyMouseClickObservers += ProcessMouseClick;
	}

	void Start()
    {
        thirdPersonCharacter = GetComponent<ThirdPersonCharacter>();
        currentDestination = transform.position;  
        aiCharacterControl = GetComponent<AICharacterControl>(); 
    }

    void ProcessMouseClick(RaycastHit raycastHit, int layerHit)
    {
        print("Click"); 
    }

    //TODO Make this get called again
    void ProcessDirectMovement()
    {
        Debug.Log("In direct movement mode");
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        // calculate camera relative direction to move:
        // calculate move direction to pass to character
        Vector3 cameraForward = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized;
        Vector3 movement = v * cameraForward + h * Camera.main.transform.right;
        thirdPersonCharacter.Move(movement, false, false);

    }
}

The CameraRaycaster script is as follows:

public class CameraRaycaster : MonoBehaviour
{
	// INSPECTOR PROPERTIES RENDERED BY CUSTOM EDITOR SCRIPT
	[SerializeField] int[] layerPriorities;  // int value based, compared to OLD with layer types

    float maxRaycastDepth = 100f; // Hard coded value
	int topPriorityLayerLastFrame = -1; 

    public delegate void OnCursorLayerChange(int newLayer); // declare new delegate type
    public event OnCursorLayerChange notifyLayerChangeObservers; // instantiate an observer set

	public delegate void OnClickPriorityLayer(RaycastHit raycastHit, int layerHit); // declare new delegate type
	public event OnClickPriorityLayer notifyMouseClickObservers; // instantiate an observer set


    void Update()
	{

		// Check if pointer is over an interactable UI element
		if (EventSystem.current.IsPointerOverGameObject ())
		{
			NotifyObserersIfLayerChanged (5);
			return; // Stop looking for other objects
		}

		// Raycast to max depth and store in array named 'raycastHits', every frame as things can move under mouse
		Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
		RaycastHit[] raycastHits = Physics.RaycastAll (ray, maxRaycastDepth);

        RaycastHit? priorityHit = FindTopPriorityHit(raycastHits);
        if (!priorityHit.HasValue) // if hit no priority object
		{
			NotifyObserersIfLayerChanged (0); // broadcast default layer
			return;
		}

		// Notify delegates of layer change
		var layerHit = priorityHit.Value.collider.gameObject.layer;  // Too many Dots!
		NotifyObserersIfLayerChanged(layerHit);
		
        
		// Notify delegates of highest priority game object under mouse when clicked
		if (Input.GetMouseButton (0))
		{
            if (notifyMouseClickObservers != null)
            {
                Debug.Log(priorityHit.Value);
                Debug.Log(layerHit);
                notifyMouseClickObservers(priorityHit.Value, layerHit);
            }
		}
	}

	void NotifyObserersIfLayerChanged(int newLayer)
	{
		if (newLayer != topPriorityLayerLastFrame)
		{
			topPriorityLayerLastFrame = newLayer;
			notifyLayerChangeObservers (newLayer);
		}
	}

	RaycastHit? FindTopPriorityHit (RaycastHit[] raycastHits)
	{
		// Form list of layer numbers hit
		List<int> layersOfHitColliders = new List<int> ();
		foreach (RaycastHit hit in raycastHits)
		{
			layersOfHitColliders.Add (hit.collider.gameObject.layer);
		}

		// Step through layers in order of priority looking for a gameobject with that layer
		foreach (int layer in layerPriorities)
		{
			foreach (RaycastHit hit in raycastHits)
			{
				if (hit.collider.gameObject.layer == layer)
				{
					return hit; // stop looking
				}
			}
		}
		return null; 
	}
}

CursorAffordance Script:

[RequireComponent (typeof(CameraRaycaster))]
public class CursorAffordance : MonoBehaviour {

    [SerializeField] Texture2D walkCursor = null;
    [SerializeField] Texture2D targetCursor = null;
    [SerializeField] Texture2D unknownCursor = null; 

    [SerializeField] Vector2 cursorHotspot = new Vector2(0 , 0);  // The actual clicking point on the cursor

    //TODO solve fight between serialize and const
    [SerializeField] const int walkableLayerNumber = 9;
    [SerializeField] const int enemyLayerNumber = 10;
    [SerializeField] const int deadLayerNumber = 11;

    CameraRaycaster cameraRaycaster;

	void Start() {
        cameraRaycaster = GetComponent<CameraRaycaster>();
        cameraRaycaster.notifyLayerChangeObservers += OnLayerChangeForCursor;  // Registering to oberver list.
	}
	
	// Only called when layer changes.
	void OnLayerChangeForCursor(int newLayer) {
        
        switch (newLayer) // Used to say "switch (cameraRaycaster.currentLayerHit)" before we passed parameters with delegates.
        {
            case walkableLayerNumber:
                Cursor.SetCursor(walkCursor, cursorHotspot, CursorMode.Auto);
                break;
            case enemyLayerNumber:
                Cursor.SetCursor(targetCursor, cursorHotspot, CursorMode.Auto);
                break;
            default:
                //Debug.LogError("Don't know what cursor to show");
                Cursor.SetCursor(unknownCursor, cursorHotspot, CursorMode.Auto);
                return;
        }
        
	}
}

Thank you so much. I know this is a lot.

Can you confirm which line the error is on, in the above it states line 81, but that would be a closing brace at present, so it clearly isn’t that.

Note, if you don’t post full scripts then the line numbers don’t match up when other people check your code, case in point, all of the missing using directives etc.

If it’s easier, share the project with me and I’ll take a look. The forum will allow uploads of up to 10mb, your project is likely to be larger than that you’ll need to use a service such as Google Drive or Dropbox. Please zip the project files and then share the URL and I’ll take a look for you. :slight_smile:

I am sorry. I removed all my comments since I take deep notes during the lectures. The error is on the:

if (Input.GetMouseButton (0))
{
    if (notifyMouseClickObservers != null)
    {
        Debug.Log(priorityHit.Value);
        Debug.Log(layerHit);
        notifyMouseClickObservers(priorityHit.Value, layerHit);
    }
}

When double clicking the error in the console, it takes me to “notifyMouseClickObservers(priorityHit.Value, layerHit);” line.

Ok, can you share the project files with me please.

Privacy & Terms