Hey!
I am trying to keep track of every enemy in a wave-based 3D game, and to do this I’m trying to use events to send out every time an enemy spawns and dies. This worked at first when I just used an int to add and subtract every time the enemies spawned and despawned, but it had a bug where if multiple enemies died at the same time, sometimes the enemycount went into the negatives or stayed in the 1-9 area. I assumed this was because when the event didnt remove them properly, so I tried to switch to a list, where everytime an enemy spawns it sends an event to the spawner keeping track of all gameobjects in a list. However, when I try to do this it just gives me the typical null-reference.
(Object reference not set to an instance of an object), however when I debug.log the gameobject it knows which gameobject it should be refered to.
Any idea on why this happens? or any other suggestions on how to fix the initial issue?
me = this.gameObject;
GameEventsManager.instance.enemyEvents.Spawn( me);
the event manager then goes like this
public class GameEventsManager : MonoBehaviour
{
public static GameEventsManager instance { get; private set; }
[NonSerialized] public EnemyEvents enemyEvents;
private void Awake()
{
instance = this;
enemyEvents = new EnemyEvents();
}
}
leading to the enemyevents-script
public class EnemyEvents
{
public event Action<GameObject> OnDeath;
public void Death(GameObject gameObject)
{
if (OnDeath != null)
{
OnDeath(gameObject);
}
}
public event Action<GameObject> OnSpawn;
public void Spawn(GameObject gameObject)
{
if (OnSpawn != null)
{
OnSpawn(gameObject);
}
}
}
The error is on the ‘TotalEnemies.Add(Shadow)’, which sends my to the initial enemyline of ‘GameEventsManager.instance.enemyEvents.Spawn( me);’ in the enemyscript, when i double click the error in unity.
Honestly that looks like a “defective half singleton” pattern to me.
A better “transient service” model is to set the instance to this in OnEnable(), then set it back to null in OnDisable() to keep everybody honest so to speak, but I have no idea of your intended lifecycle of this GameEventManager.
Do you understand the intended lifecycle of this “half singleton” GameEventManager you have?
Some super-simple Singleton examples to take and modify:
Simple Unity3D Singleton (no predefined data):
Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:
These are pure-code solutions, DO NOT put anything into any scene, just access it via .Instance
Alternately you could start one up with a [icode]RuntimeInitializeOnLoad[/icode] attribute.
NullReference is the single most common error while programming. Fixing it is always the same.
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
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:
Identify what is null ← any other action taken before this step is WASTED TIME
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.
Well I see one major issue here as well as some things that could be changed.
First making a variable to make a reference to a gameobject within its own script is redundant. You could instead just use GameEventsManager.instance.enemyEvents.Spawn(gameObject); and it would accomplish the same thing.
Second, when you are making a static instance you should also destroy any duplicate instances if one exists. In your awake it should be:
You are also not invoke the event at any point, in your Spawn method it should be:
public void Spawn(GameObject gameObject)
{
//the ? operand does the same thing is if (OnSpawn != null) but is shorter
OnSpawn?.Invoke(gameObject);
}
And for the major issue which is probably causing your null reference issue, your EnemyEvents script does not derive from MonoBehaviour and can’t work with GameObjects. What you should do is not make a new EnemyEvents class in the GameEventsManager Awake but instead make EnemyEvents derive from MonoBehaviour, put it on the same GameObject that the GameEventsManager is on and then add the reference to it by either dragging and dropping in the inspector or using GetComponent in Awake to find it.
One more side note, I’d personally just add the events to your GameEventsManager script rather than making a whole separate script for each type of event there is.