I’ve been using Unity Events for a few weeks now, and whilst they are useful I was finding it restrictive not having an obvious way to pass arguments and not being able to tell which object sent the event. I knew there must be a way around the first problem as the UI system has events with a single parameter, but I to achieve both my goals I need to be able to pass two parameters.
After a bit of playing around I came up with this solution which seems to do the job perfectly, and as far as I can see allows the passing of an arbitrary amount of data.
To run this example you will need to set up a scene with a GameObject for the player, (I chose a capsule), and attach the following script to it.
using UnityEngine;
using System.Collections;
using UnityEngine.Events;
public class Player : MonoBehaviour {
public HealthChangedEvent healthChanged;
public int health {
get;
private set;
}
// Use this for initialization
void Start () {
SetHealth(100);
}
// Update is called once per frame
void Update () {
if(Input.GetKeyDown(KeyCode.Space))
{
SetHealth(health-10);
}
}
void SetHealth(int amount)
{
health = amount;
healthChanged.Invoke(new HealthChangedEventArgs(gameObject,health));
}
}
[System.Serializable]
public class HealthChangedEvent : UnityEvent<HealthChangedEventArgs> {}
public class HealthChangedEventArgs
{
public object sender;
public int health;
public HealthChangedEventArgs (object sender, int health)
{
this.sender = (object)sender;
this.health = health;
}
}
All this does is set the player’s health to 100 when it starts, and then reduces it by 10 every time you press space. It also sends an event whenever the health value changes.
To test the event, you can add a canvas with a text component to the scene, and add the following script to the canvas.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class HUDCanvas : MonoBehaviour {
[SerializeField] Text healthText;
public void OnPlayerHealthChanged(HealthChangedEventArgs e)
{
healthText.text = "GameObject " + ((GameObject)e.sender).name + " updated it's health to " + e.health.ToString();
}
}
In the inspector you’ll need to drag your Text component onto the healthText field.
Lastly you need to hook up your Player HealthChanged event, by selecting the Player gameobject in the inspector, clicking the + button on the HealthChangedEvent, then drag your canvas into the new event and select OnPlayerHealthChanged from the very top of the list of function available from the HUDCanvas script.
When this runs it will change the text to reflect the player’s health whenever it changes and also display the name of the gameobject that invoked the event.
The EventArgs class can be customised to pass whatever data you want when the event is invoked. I hope somebody else finds this at least a bit useful.
Let me know if you have any questions or need help getting it working.