Inheriting values from ScriptableObjects?

Hi all,

So this is a seemingly simple problem but I’ve searched and tested different solutions for hours to no avail. I’m new to ScriptableObjects and they seem simple enough but when I try to retrieve data through them using another script I receive the ol’ NullReferenceException when it tries to call floors.GenerateFloors(settings) and levels.GenerateLevels(settings).

I’m creating a building generator. I’ve created a ScriptableObject for all of my various building settings, size, levels, glazing percentage, prefab pieces, etc… I want each part to have their own script so they’re easy to debug such as floors, walls, roofs and anything else that I may want to add in the future. The thought process is that I pass information from my BuildingSettings ScriptableObject into the floors or walls class which has methods to do whatever they need to do. I then call those methods from my BuildingGenerator MonoBehaviour which references the ScriptableObject attached to it. The problem is that the data is not being referenced when passed through my GenerateFloors or GenerateLevels methods. When I call those methods they return Null. When I call the variables straight from the BuildingSettings ScriptableObject (the commented out Debug.Log lines you see in the BuildingGenerator) it returns the correct value. I’ve tried a few different methods of retrieving the data with no luck. I’m assuming it’s due to my own ignorance of either ScriptableObjects or how methods pass data from one to the next but everything I’ve read makes it seem like what I’m doing isn’t out of the ordinary so I’m not sure where to turn. The thought process is that the methods are arbitrarily referencing the BuildingSettings type but when I run it in my MonoBehaviour it’s referencing what’s attached to the GameObject, but that’s clearly not happening. Any tips? Thanks in advance.


Building Generator:

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

public class BuildingGenerator : MonoBehaviour
{
    public FloorSetup floors;
    public RoofSetup roofs;
    public WallSetup walls;
    public LevelSetup levels;

    public BuildingSettings settings;

    public void Start()
    {


        floors.GenerateFloors(settings);
        levels.GenerateLevels(settings);
        
        //walls.GenerateWalls(settings);
        //roofs.GenerateRoof(settings);
       
        //Debug.Log(settings.MinSizeX);
        //Debug.Log(settings.MaxSizeY);
        //Debug.Log(settings.MaxLevels);

    }

}

Building Settings:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CreateAssetMenu(menuName = "Building Generator/Building Settings", order = 55)]
public class BuildingSettings : ScriptableObject
{

    [Header("Building Size")]
    public int minimumSizeX;
    public int maximumSizeX;
    
    public int MinSizeX { get { return minimumSizeX; } }
    public int MaxSizeX { get { return maximumSizeX; } }

    public int minimumSizeY;
    public int maximumSizeY;

    public int MinSizeY { get { return minimumSizeY; } }
    public int MaxSizeY { get { return maximumSizeY; } }


    [Range(0.1f, 1.0f)]
    public float floorTileInfill;

    [Header("Building Levels")]

    public int minNumLevels;
    public int maxNumLevels;
    
    public int MinLevels { get { return minNumLevels; } }
    public int MaxLevels { get { return maxNumLevels; } }
    
    public bool varyEachLevel;

    //[Header("Building Glazing")]  
    //public int glazingPercentageRange;

    [Header("Building Parts")]
    public Transform[] floorTiles;
    public Transform[] walls;
    public Transform[] Roofs;
    public Transform[] windows;


}

Level Setup:

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

public class LevelSetup
{
    public int numberOfLevels;

    public void GenerateLevels(BuildingSettings settings)
    {
        numberOfLevels = UnityEngine.Random.Range(settings.MinLevels, settings.MaxLevels);

        Debug.Log(numberOfLevels);

    }
}

Floor Setup:

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

public class FloorSetup
{

    public int buildingSizeX;
    public int buildingSizeY;

    public void GenerateFloors(BuildingSettings settings)
    {

        buildingSizeX = UnityEngine.Random.Range(settings.MinSizeX, settings.MaxSizeX);
        buildingSizeY = UnityEngine.Random.Range(settings.MinSizeY, settings.MaxSizeY);

        Debug.Log(buildingSizeX);
        Debug.Log(buildingSizeY);
        
    }
}

Your LevelSetup, FloorSetup classes are not marked as serializable. So the inspector will not create an instance of those classes for you. Therefore your “floor” variable will be null unless you create an instance manually.

Nice surprise to wake up and see that there’s an answer to a question that I didn’t even know I posted lol. Kept getting errors when trying to post this last night, apparently one went through.

Anyway, thank you for the quick reply. In the context of what I know about serialized fields, that makes a lot of sense. By making it serialized, it’s just creating a location in memory for any data within that class to be stored which I can then access with my MonoBehaviour, correct? So in the future, any class that I’ll be passing data through that I’d like to effect, I need to serialize before passing it to my MonoBehaviour? My assumption is that MonoBehaviours are serialized, so when a class inherits from MonoBehaviour, it’s serialized by default?
Sorry for all of the follow-up questions, I’d just like to understand the behavior so I can troubleshoot without having to bug you fine people in the future. Not gonna lie, I don’t know how I didn’t come across this solution when I was searching for ways to fix this, everything seemed a lot more convoluted than your response.