Unity says my GameObject variable is not set, but it is.

As I mentioned in the title, my script that I wrote below, is giving me errors when I call LevelUp() method from a button in UI system. In the inspector, it is assigned. It all happens in the same script. The “unassigned” object is the selectedObject variable. I restarted Unity, look out for another instance of FactoryManager component, but none of it worked for me. I will very appreciate your help!

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FactoryManager : MonoBehaviour {


    public List<GameObject> factories;
    public int selectedFactoryId;
    [SerializeField] private GameObject selectedObject;
    [SerializeField] private GameObject gameManager;
    [SerializeField] private LayerMask mask;
    private GameObject factoryPanel;
    GameObject moneyToNextLevelText;
    GameObject factoryLevelText;
    GameObject factoryNameText;
    Image factoryLevelBar;
    


    public void AddNewFactory(GameObject factoryToAdd)
    {
        factories.Add(factoryToAdd);
    }

	void Start ()
    {
        selectedFactoryId = 1;
        gameManager = GameObject.FindGameObjectWithTag("GameManager");
        factoryPanel = GameObject.Find("FactoryMenu");
        moneyToNextLevelText = factoryPanel.transform.Find("LevelButton").Find("MoneyToNextLevel").gameObject;
        factoryLevelText = factoryPanel.transform.Find("FactoryLevelText").gameObject;
        factoryNameText = factoryPanel.transform.Find("FactoryName").gameObject;
        factoryLevelBar = factoryPanel.transform.Find("LevelButton/Bar/Background").gameObject.GetComponent<Image>();
    }
	
	void Update ()
    {
        if (Input.touchCount == 1)
        {
            if (Input.GetTouch(0).phase == TouchPhase.Began)
            {
                RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint((Input.GetTouch(0).position)), Vector2.zero, Mathf.Infinity, mask);
                if (hit.collider != null)
                {
                    selectedObject = hit.transform.gameObject;
                }
            }
            if (Input.GetTouch(0).phase == TouchPhase.Ended)
            {
                RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint((Input.GetTouch(0).position)), Vector2.zero, Mathf.Infinity, mask);
                if (hit.collider != null)
                {
                    if (hit.transform.gameObject == selectedObject)
                    {
                        SelectFactory(selectedObject);                  
                    }

                }
                else
                {
                    selectedObject = null;
                }
            }
        }
    }

    public void SelectFactory(GameObject selectedFactory)
    {

        selectedFactoryId = selectedFactory.GetComponent<Factory>().factoryListId;

        //Set factory panel values to current factory.

        RefreshFactoryUI(selectedFactory);

        //Open factory panel.

        gameManager.GetComponent<FactoryMenu>().OpenFactoryMenu();

        Camera.main.transform.position = new Vector3(Mathf.Lerp(Camera.main.transform.position.x, selectedFactory.transform.position.x + 1, 0.2f), 0, 0);

    }

    public void RefreshFactoryUI(GameObject selectedFactory)
    {
        
        
        factoryLevelBar.fillAmount = selectedFactory.GetComponent<Factory>().GetStageLevelRatio();

        factoryNameText.GetComponent<Text>().text = selectedFactory.name;
        
        factoryLevelText.GetComponent<Text>().text = "Level " + selectedFactory.GetComponent<Factory>().factoryLevel;

        moneyToNextLevelText.GetComponent<Text>().text = "" + selectedFactory.GetComponent<Factory>().moneyToNextLevel;
    }

    public void LevelUp()
    {
        print(selectedObject.name);
    }
}

The problem is probably with the LevelUp() then, maybe your UI button referred to the script in the prefab instead of the game object in the scene. When choosing an object for the button to access, select the “Scene” tab instead of the “Assets” tab

I must assume that when LevelUp is called, you know that the FactoryManager’s Update processed touch, found a selectedObject and initialized it.


As khooroko pointed out, mask has not been initialized but I assume Raycast is ignoring that, perhaps using the default mask. My assumption is based on the previous assumption, that you know the Raycast did find a selectedObject. Since you’re using the default for the 3rd parameter, and don’t appear to care about the layers mask would filter, you should probably edit the calls to Raycast to skip those parameters and let the defaults apply.


If you intend that FactoryManager should operate as a singleton, but don’t want, for whatever reason, to use static member variables to ensure it operates that way, you could ensure there are no multiple FactoryManagers with a static member variable which tracks the manager and alerts you if multiple instantiations happen to appear via Start or Awake.


If we assume that FactoryManager’s Update was called in the appropriate context, and that there is only one FactoryManager, and that selectedObject was in fact set when the TouchPhase ended, then we must turn attention to the one place where selectedObject is made null, the “else” clause to the hit.collider test for null within the “ended” touchphase. If that is the only place selectedObject is set to null, it is likely associated.


Perhaps FactoryManager’s Update is still being called when you are expecting some other UI phase is active, and the touch is still being processed at a time after selectedObject is set, and you’re not able to tell. Even though you declare the inspector shows selectedObject is set, you should be aware that the inspector is not necessarily updated live; it can be behind the real state of member variables (things happen fast).


Consider what would happen if FactoryManager’s update is being called even though other UI or game function is processing. If Raycast returns a null collider at the end of a touchphase, when in fact a selectedObject was previously assigned, this would set it to null. Perhaps this is coincident with the touch release of the very button you’re calling LevelUp from, and so it is being nulled just prior to the call, but too fast for the inspector to update.


You may need to deactivate this script, or otherwise disable Update’s touch processing when the context of the game does not require it.