NullReferenceException when accessing base class variable on inactive gameobject

Good morning all, and thanks in advance for your time!

I very recently learned about virtual/override/abstract functions, and am trying to utilize that knowledge to re-write my save system. Effectively, I have the following script/class heirarchy:

  • scrDictionaryFlag (base class - contains flagID and flagValue strings for saving)
  • scrEnemy (child class, inherits scrDictionaryFlag, provides basic values and code for generic enemies)
  • various specific enemy scripts that inherit scrEnemy, but then have specific behaviors for those enemies

scrDictionaryFlag is set up to basically be the base class for ANY object that needs to be saved, so it is the base class for all dynamic objects - enemies, doors, destructible objects, etc. When the save function is called, the game finds every object in the scene that contains the “scrDictionaryFlag” class, and calls a function “setFlag”, which is a virtual void on the base, with an override on the individual enemy script, which basically has that object gather all of it’s data needed for save/load and prepare it to be written to file. Once the save strings are all prepared, it iterates through these objects again and saves the key/value pair (flagID/flagValue) to file. This works perfectly for active gameobjects.

However, if a gameobject is inactive, I get a NullReferenceException when calling setFlag. I use FindObjectsOfType to gather the list of Dictionary Flags, which also looks for inactive objects, and this same method works perfectly when loading a save and writing flagValues back to those objects. It’s only when trying to call setFlag, a script on the specific enemy script, which attempts to modify “flagValue”, a string inherited from the base class, on an inactive object, where this error occurs.

Code blocks below:

scrDictionaryFlag, the base class

public class scrDictionaryFlag : MonoBehaviour
{
    public string flagID;
    public string flagValue;

    public virtual void Awake()
    {
        if (flagID.Length <= 0)
        {
            flagID = System.Guid.NewGuid().ToString();
        }
    }

    public virtual string getFlag()
    {
        print("Parent getFlag was called!");

        return "";
    }
    public virtual void setFlag()
    {
        print("Parent setFlag was called!");
    }
}

… the system script where the dictionary objects are all gathered and setFlag is called

List<scrDictionaryFlag> flagList = new List<scrDictionaryFlag>();
            foreach (scrDictionaryFlag flag in FindObjectsOfType<scrDictionaryFlag>(true))
            {
                if (flag.flagID == null || flag.flagID.Length == 0)
                {
                    flag.flagID = System.Guid.NewGuid().ToString();
                }
                flag.setFlag();
                if(flag.getFlag().Length == 0)
                {
                    Debug.Log("No save data detected for " + flag.gameObject.name);
                }
                if (!flag.flagValue.StartsWith("ignore"))
                {
                    flagList.Add(flag);
                }
            }

And the “setFlag” function which appears in all of the specific enemy scripts:

    public override void setFlag()
    {
        flagValue =
"enemy" + "|"
+ prefabID.ToString() + "|"
+ transform.position.x.ToString() + "|"
+ transform.position.y.ToString() + "|"
+ transform.position.z.ToString() + "|"
+ transform.rotation.x.ToString() + "|"
+ transform.rotation.y.ToString() + "|"
+ transform.rotation.z.ToString() + "|"
+ transform.rotation.w.ToString() + "|"
+ rigidBody.velocity.x.ToString() + "|"
+ rigidBody.velocity.y.ToString() + "|"
+ rigidBody.velocity.z.ToString() + "|"
+ hp.ToString() + "|"
+ currentSprite.ToString() + "|"
+ currentFrame.ToString() + "|"
+ frameAdvance.ToString() + "|"
+ spriteSpeed.ToString() + "|"
+ this.gameObject.activeInHierarchy.ToString();
    }

The specific error occurs on the line “flagValue =” in the above code.

NullReferenceException: Object reference not set to an instance of an object
scrSpecificEnemy.setFlag ()

Here are some specific things I’ve tried with no success:

  • Removed the bulk of the “flagValue” assignment, and just set it to a static string of “flag”, to rule out an issue where one of the several variables being written to file is causing the issue
  • Tested in scenarios where the gameobjects are active at game start, then inactive on save. Whether or not the gameobject is active at game start doesn’t seem to matter - only if the object is active on save
  • Manually set the value of “flagValue” via Inspector so it isn’t null

No surprise, it’s an 18-line statement! One of those things is null and the way it is written, there is no easy way to see, short of attaching a debugger and freezing your game.

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.

And again, it doesn’t really matter what you’re doing.

The answer is always the same… ALWAYS. It is the single most common error ever.

Don’t waste your life spinning around and round on this error. Instead, learn how to fix it fast… it’s EASY!!

Some notes on how to fix a NullReferenceException error in Unity3D

  • also known as: Unassigned Reference Exception
  • also known as: Missing Reference Exception
  • also known as: Object reference not set to an instance of an object

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

The basic steps outlined above are:

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

Expect to see this error a LOT. It’s easily the most common thing to do when working. Learn how to fix it rapidly. It’s easy. See the above link for more tips.

You need to figure out HOW that variable is supposed to get its initial value. There are many ways in Unity. In order of likelihood, it might be ONE of the following:

  • drag it in using the inspector
  • code inside this script initializes it
  • some OTHER external code initializes it
  • ? something else?

This is the kind of mindset and thinking process you need to bring to this problem:

https://discussions.unity.com/t/814091/4

Step by step, break it down, find the problem.

Here is a clean analogy of the actual underlying problem of a null reference exception:

https://discussions.unity.com/t/840647/7

Appreciate the reply!

This was of course my first thought, but as I mentioned, this was one of the things I’ve tried:

  • Removed the bulk of the “flagValue” assignment, and just set it to a static string of “flag”, to rule out an issue where one of the several variables being written to file is causing the issue

Basically I tried it where flagValue is just set to “0” rather than that huge string of variables, and the issue persisted.

So you’re saying flagValue = "0"; throws a null reference?

What happens if you delete that line?

And how are you making this MonoBehaviour? Is it already in place, or are you instantiating it, or are you calling .AddComponent(); ? Any other way is invalid. For instance you cannot use new

EDIT: I just noticed this is a save system. Are you relying on JSON making one of these things? That won’t work either. You must make the MonoBehaviour instance yourself (on a valid GameObject), then populate it with JSON data.

Here’s more random Load/Save steps:

Don’t use the binary formatter/serializer: it is insecure, it cannot be made secure, and it makes debugging very difficult, plus it actually will NOT prevent people from modifying your save data on their computers.

When loading, you can never re-create a MonoBehaviour or ScriptableObject instance directly from JSON. The reason is they are hybrid C# and native engine objects, and when the JSON package calls new to make one, it cannot make the native engine portion of the object.

Instead you must first create the MonoBehaviour using AddComponent() on a GameObject instance, or use ScriptableObject.CreateInstance() to make your SO, then use the appropriate JSON “populate object” call to fill in its public fields.

If you want to use PlayerPrefs to save your game, it’s always better to use a JSON-based wrapper such as this one I forked from a fellow named Brett M Johnson on github:

Well shoot, I feel like I just wasted several hours of my life haha

I went back and re-tried setting the flagValue assignment to something static, and this time, it did clear up the error, which is … just majorly frustrating because I tried this same thing once last night, and again this morning, and in both cases the error persisted. Maybe Unity’s console was running as behind as my brain.

Anyway, I think you were right after all that it is one of the multiple assigned variables causing the issue, and I think I know which one is the culprit.

Thanks for the dose of common sense, and once again, the hoofbeats were horses.

Ah yeah, been there, done that. The only defense I have is to do something like I suggested, just delete the code… and when the error continues you can be pretty sure there’s some OTHER code you haven’t even considered. Or else put a Debug.Log() right in there and when that doesn’t fire, you know something is fishy.

Sometimes Unity gets into a state where it just doesn’t recompile changes to code, despite no changes in settings. Usually closing Unity, blowing away the Library/ScriptAssemblies folder, and reopening Unity.