NullRefrenceExeption, but object is assigned

I have a GUI script that finds objects/scripts on an instantiated player by ORK framework. This code was working perfectly until just recently. No idea what caused it to stop… Help would be greatly appreciated! The objects are assigned in the editor on the UI panel. Rundown below.

Instantiate player>look for script components attached to player and camera objects>control UI

Basically not finding the scripts anymore, where it was before.

using ORKFramework;
using UnityEngine;
using UnityEngine.EventSystems;

public class rmenu : MonoBehaviour

{
    public vp_FPCamera camscript;
    public vp_FPController controller;

    //public vp_FPInput input;
    public vp_SimpleCrosshair crosshair;

    public BuildManager bman;
    private EventSystem eventsys;

    [SerializeField]
    private uPIeMenu subMenu1;

    [SerializeField]
    private uPIeMenu subMenu2;

    private bool isShowing;

    [SerializeField]
    private string triggerButtonName = "TogglePingMenu";

    [SerializeField]
    private uPIeMenu relatedMenu;

    public string TriggerButtonName
    {
        get { return triggerButtonName; }
        set { triggerButtonName = value; }
    }

    public uPIeMenu RelatedMenu
    {
        get { return relatedMenu; }
        set { relatedMenu = value; }
    }

    public uPIeMenu SubMenu1
    {
        get { return subMenu1; }
        set { subMenu1 = value; }
    }

    public uPIeMenu SubMenu2
    {
        get { return subMenu2; }
        set { subMenu2 = value; }
    }

    private void Start()
    {
        camscript = (vp_FPCamera)GameObject.Find("FPSCamera").GetComponent("vp_FPCamera");
        //input = (vp_FPInput)GameObject.Find("Player").GetComponent("vp_FPInput");
        controller = (vp_FPController)GameObject.Find("Player").GetComponent("vp_FPController");
        crosshair = (vp_SimpleCrosshair)GameObject.Find("Player").GetComponent("vp_SimpleCrosshair");
        eventsys = (EventSystem)GameObject.Find("EventSystem").GetComponent("EventSystem");
        bman = (BuildManager)GameObject.Find("BuildManager").GetComponent("BuildManager");
        camscript.enabled = true;
        controller.enabled = true;
        crosshair.enabled = true;
    }

    private void Update()
    {
        if (!ORK.Control.Blocked //Check if ORK controls register as blocked for player
            && Input.GetMouseButtonDown(2)) //Also check if middle mouse button is pressed
        {
            crosshair.enabled = !crosshair.enabled;
            controller.enabled = !controller.enabled;
            //input.enabled = !input.enabled;
            camscript.enabled = !camscript.enabled; //Check if cam is currently blocked
            isShowing = !isShowing; //Check if menu is showing or not
            //{
            //    relatedMenu.transform.localPosition = Vector3.zero;//Use current mouse vector to display menu
            //}
            if (Input.GetMouseButtonDown(0) //Use Mouse Button 0 to confirm current selection on close
                && (eventsys.IsPointerOverGameObject()))
            {
                relatedMenu.ConfirmCurrentSelection(); //Use currently highlighted selection on menu close
            }
            subMenu1.ReturnToSuperMenu(relatedMenu);
            subMenu2.ReturnToSuperMenu(relatedMenu);
            relatedMenu.gameObject.SetActive(isShowing); //Show or close menu
        }
    }

    public void placeobjectmenu()
    {
        if (!ORK.Control.Blocked)
        {
            bman.SelectBuilding(0);
            bman.ActivateBuildingmode();
            relatedMenu.gameObject.SetActive(!isShowing);
            isShowing = !isShowing;
            camscript.enabled = !camscript.enabled;
            crosshair.enabled = !crosshair.enabled;
            controller.enabled = !controller.enabled;
        }
    }
}

You should consider using the templated version of .GetComponent<>(), like so:

camscript = GameObject.Find("FPSCamera").GetComponent<vp_FPCamera>();

If you do that you get strong type checking and don’t have to cast it. If a class is renamed and you fail to update the string, you will get compiler errors and know to fix it.

Thank you much! Still no joy after changing those lines. I am getting the same error. Any other ideas?

Do you have an object named FPSCamera in your hierarchy? GameObject.Find is likely returning null, which then throws the exception when you try to call GetComponent on it. Split your code into two lines:

    GameObject c = GameObject.Find("FPSCamera");
    if (c == null)
    {
       Debug.Log("FPS Camera not found");
    }

    camscript = c.GetComponent<vp_FPCamera>();
1 Like

GameObject.Find is almost certainly the trouble. As the other comments have hinted, it’s really easy for GameObject.Find to break. Mistyping a lowercase as a capital will break it. Instantiating the object you’re finding will break it (because it adds ‘Clone’ to it). Truth is that GameObject.Find is never ever the best way to accomplish what you’re going for (with the exception of debug or inspector code) - the only reason to use it is because you don’t know the alternatives available, which always improve on the reliability or performance of GO.F (or both!).

The main alternatives:

A) If possible, the simplest solution is to assign these variables in the inspector - just drag your player into the slots labeled ‘controller’ and ‘crosshair’ in your menu’s Inspector pane. In terms of reliability - if something breaks, it’ll be immediately visible in the inspector. In terms of performance - this is instantaneous.

B) If that’s not an option, the singleton pattern is an option, which will let you find an object anywhere if it’s the only script of its type in the game:

public class vp_FPController : MonoBehaviour {
public static vp_FPController main;

void Awake() {
main = this;
}
// in your menu script
vp_FPController.main.enabled = !vp_FPController.main.enabled;

The singleton is also basically instantaneous, and even more reliable than the inspector assignment, as it will still find objects that are loaded from other scenes additively and so on.

C) If that’s not an option, you can use FindObjectOfType<vp_FPController>() or FindObjectsOfType if there’s more than one. This is almost as slow as GameObject.Find, so it’s not the best alternative, but it’s a lot more reliable, as it doesn’t care what the name of the thing is - it’ll find an instance of that script, anywhere in the scene.

Thank you all for your replies!

StarManta,

So, what are you proposing I use in place of GO.F to define the actual camscript for option2? I’m still very much learning C# and clarification is much appreciated! :slight_smile:

I’m not sure I follow the question? If you’re using a singleton, you remove the GameObject.Find line and the local variable (camscript) entirely - the vp_FPSController script (in this example) takes on those responsibilities, and you replace “camscript” with vp_FPSController.main anywhere you use it.

Ok, understood now! Both scripts have been modified appropriately with no errors. I still get the same error in Unity, however. How is this possible…? I must be missing something.

Which line does the error point to when you double-click it?

My apologies, I rechecked and had an errant line of code still in my menu script. Thanks very much for your time and teaching!

Always happy to remove GameObject.Find from a script :wink: