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