Scriptable Object not being assigned to, which stops me from calling on its variables.

So I have two scripts. One called Selectable Object which stores all the information for a specific object like its name, description, resource type, and some images. Here is that code:

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

[CreateAssetMenu(fileName = "New Object", menuName = "Selectable")]
public class SelectableObject : ScriptableObject
{
    public Image resourceImage;
    public string resourceType;
    public Image preview;
    public string itemName;
    public string description;
    public GameObject selectable;
    public int costToBuild;
}

Now I’m trying to access these variables so I can assign them to text fields and images on a canvas. I am able to call on it just fine I believe but I get stuck when trying to assign a text field to the description variable declared in the scriptable object. Here is the code:

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

public class BuildMenu : MonoBehaviour
{
    public Canvas canvas;
    public GameObject objectPanel, preview, description, cost, resource, itemName;
    public List<ScriptableObject> basics;
    private SelectableObject selectableObject;
    // Start is called before the first frame update
    void Start()
    {
        canvas = GetComponent<Canvas>();
        objectPanel = canvas.transform.Find("ObjectPanel").gameObject;
        BasicsPanel();
    }

    // Update is called once per frame
    void Update()
    {
    }

    public void BasicsPanel()
    {
        int x = 0;
        foreach (ScriptableObject scriptable in basics)
        {
            GameObject panel = Instantiate(objectPanel, canvas.transform);
            selectableObject = Resources.Load<SelectableObject>(basics[x].name);
            Debug.Log(basics[x].name);
            preview = objectPanel.transform.Find("ObjectPreview").gameObject;
            description = objectPanel.transform.Find("Description").gameObject;
            cost = objectPanel.transform.Find("TileCost").gameObject;
            resource = objectPanel.transform.Find("ResourceRequirement").gameObject;
            itemName = objectPanel.transform.Find("ItemName").gameObject;
            Vector3 pos = panel.transform.position;
            panel.SetActive(true);
            if(x >= 1)
            {
                pos.x = (panel.transform.position.x + 310);
                Debug.Log(panel.transform.position + " : " + pos);
            }
            panel.transform.position = pos;
            TextMeshPro tmpDescription = description.GetComponent<TextMeshPro>();
            tmpDescription.text = selectableObject.description;
            x++;
        }
    }
}

The problem comes in at line 48 where I am assigning the text to “selectableObject.description”. It throws a NullReference error. I’m not sure what the problem is, can anyone help me solve this?

UPDATE**
So I figured out how to load it correctly by using the resources folder. But I am still having issues assigning the text to the description even though the description ISNT null.
Here is the new code:

foreach (ScriptableObject scriptable in basics)
        {
            GameObject panel = Instantiate(objectPanel, canvas.transform);
            selectableObject = Resources.Load<SelectableObject>("ScriptableObjects/" + basics[x].name);
            Debug.Log(selectableObject.name + " : " + selectableObject.description);
            preview = objectPanel.transform.Find("ObjectPreview").gameObject;
            description = objectPanel.transform.Find("Description").gameObject;
            cost = objectPanel.transform.Find("TileCost").gameObject;
            resource = objectPanel.transform.Find("ResourceRequirement").gameObject;
            itemName = objectPanel.transform.Find("ItemName").gameObject;
            Vector3 pos = panel.transform.position;
            panel.SetActive(true);
            if(x >= 1)
            {
                pos.x = (panel.transform.position.x + 310);
                Debug.Log(panel.transform.position + " : " + pos);
            }
            panel.transform.position = pos;
            TextMeshPro tmpDescription = description.GetComponent<TextMeshPro>();
            tmpDescription.text = selectableObject.description;
            x++;
        }

I also have here the message recieved by console:

SOLUTION:

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

public class BuildMenu : MonoBehaviour
{
    public Canvas canvas;
    public GameObject objectPanel, preview, description, cost, resource, itemName;
    public List<ScriptableObject> basics;
    private SelectableObject selectableObject;
    // Start is called before the first frame update
    void Start()
    {
        canvas = GetComponent<Canvas>();
        objectPanel = canvas.transform.Find("ObjectPanel").gameObject;
        BasicsPanel();
    }

    // Update is called once per frame
    void Update()
    {
    }

    public void BasicsPanel()
    {
        int x = 0;
        foreach (ScriptableObject scriptable in basics)
        {
            //Assigns all variables to the new panel being creates
            GameObject panel = Instantiate(objectPanel, canvas.transform);
            selectableObject = Resources.Load<SelectableObject>("ScriptableObjects/" + basics[x].name);
            Debug.Log(selectableObject.name + " : " + selectableObject.description);
            preview = panel.transform.Find("ObjectPreview").gameObject;
            description = panel.transform.Find("Description").gameObject;
            cost = panel.transform.Find("TileCost").gameObject;
            resource = panel.transform.Find("ResourceRequirement").gameObject;
            itemName = panel.transform.Find("ItemName").gameObject;
            Vector3 pos = panel.transform.position;
            panel.SetActive(true);
            //
            //If this isn't the first panel, it moves it over so they don't overlap
            if(x >= 1)
            {
                pos.x = (panel.transform.position.x + 310);
                Debug.Log(panel.transform.position + " : " + pos);
            }
            panel.transform.position = pos;
            //
            //Assigns All Fields to the selected Scriptable Variables
            description.GetComponent<TextMeshProUGUI>().text = selectableObject.description;
            itemName.GetComponent<TextMeshProUGUI>().text = selectableObject.itemName;
            preview.GetComponent<Image>().sprite = selectableObject.preview;
            cost.GetComponent<TextMeshProUGUI>().text = selectableObject.costToBuild.ToString();
            resource.GetComponent<Image>().sprite = selectableObject.resourceImage;
            //Adds 1 to X so the next scriptable in line is added
            x++;
        }
    }
}

Turns out the correct way to declare a TMP is to use the TextMeshProUGUI identifier :confused:

Why do you have a public list of these things on line 11, then you load one by name on line 33… why not just … use it!

selectableObject = basics[x];

Also, you need to seriously break those hairy lines of code up!!

If you have more than one or two dots (.) in a single statement, you’re just being mean to yourself.

How to break down hairy lines of code:

http://plbm.com/?p=248

Break it up, practice social distancing in your code, one thing per line please.

“Programming is hard enough without making it harder for ourselves.” - angrypenguin on Unity3D forums

For future reference, there’s only three steps and it’s always the same three steps:

How to fix a NullReferenceException error

https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

Steps to success:

  • Identify what is null
  • Identify why it is null
  • Fix that