On Destroy is a good place as well, It depends on where you are using them. In the example we are using them in the same game object, and also using them between the UI.
My favorite use of Events is for utilizing Game Events as Scriptable Objects. A real good example of this would be to use it in the Health Script to notify thing that something has died.
[CreateAssetMenu(fileName = "GameObjectFloatGameEvent", menuName = "RPG/GameObjectIntGameEvent")]
public class GameObjectIntGameEvent : ScriptableObject
{
private event Action<GameObject, float> _event;
public void RegisterListener(Action<GameObject, float> action)
{
_event += action;
}
public void UnregisterListener(Action<GameObject, float> action)
{
_event -= action;
}
public void Invoke(GameObject sender, float amount)
{
_event?.Invoke(sender, amount);
}
}
We could use a string, or enum, or scriptable object that identifies the type of object what ever we want to use to describe it.
In Unity Create This Game Event called Character Died.
Now in our Heath Script Instead of Creating an Award Exp Method we use the Game Event.
In Health.cs
[SerializeField] private GameObjectFloatGameEvent characterDied;
[SerializeField] private GameObjectFloatGameEvent onHealthChanged;
private float GetAwardExp()
{
float expAmount = 0;
BaseStats stats = GetComponent<BaseStats>();
if (stats) expAmount = stats.GetStatValue(Stat.ExperienceReward);
return expAmount;
}
private void Die()
{
if (IsDead) return;
IsDead = true;
_actionScheduler.CancelCurrentAction();
if (_hasAnimator) _animator.SetTrigger(_dieHash);
if (characterDied) characterDied.Invoke(this.gameObject, GetAwardExp());
}
In Experience
[SerializeField] private GameObjectFloatGameEvent characterDied;
[SerializeField] private GameObjectFloatGameEvent onExperincedChange;
private void OnEnable()
{
if (characterDied) characterDied.RegisterListener(GainExperience);
}
private void OnDisable()
{
if (characterDied) characterDied.UnregisterListener(GainExperience);
}
private void GainExperience(GameObject sender, float amount)
{
if (sender == gameObject) return;
GainExperience(amount);// This is the Public Gain Experience from the course
}
public void GainExperience(float amount)
{
value += amount;
if (onExperincedChange) onExperincedChange.Invoke(this, value);
}
Now later if I decide that I want a system that keeps track of the number of different Enemies the Player has killed I just write that system and use the character died game event, I can have another system that keeps track of how many times the player died. If this was a multiplier style game or we had a party system where the AI Player that killed Enemies we could add an extra parameter to the Game Event for the Instigator.
Doing it this way decouples the systems. Health knows nothing about Experience, It just knows it has stats and it Died. It doesn’t care who wants to know that it died or what other systems my need to be notified. The same Goes for the Experience, it knows nothing about any of the other systems just that it needs to change it’s value.
I have also used the same Game Event Type to help Decouple the UI from my other systems, I have one Health Display for both the enemy ui and the player ui, they register to the Health Changed Game Event, One UI Script that is the same for Player Health and Enemy Health, it just Reacts to the Game Event, if the sender is not correct then it ignores the Game Event, I also have a GameObjectStatFloatGameEvent that I use for when we level up so the things that need to know what the max value is can listen for that value being changed.
The Listeners need to unregistered them selves from the event if they are disabled/destroyed. Yes this is a slightly advanced event system, the system taught in the course is a little Simpler, but the UI that the course is using is dependent on these events, the base concept of handling listening to and not listening to the event is the same. I think Sam did mention something about a Possible Race Condition when discussing the Delegates and Events or in the Actions for leveling up video, I don’t remember. The race conditions/null reference might even by talked about in the data hazards or hunting down race conditions.