Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save edwios/69c9549ce69ec919292f267416517d9b to your computer and use it in GitHub Desktop.
Save edwios/69c9549ce69ec919292f267416517d9b to your computer and use it in GitHub Desktop.
Events and Delegates for Unity (C#)
Events & Delegates
------------------
Events and Delegates were something I struggled with when I was first learning how they worked. Once I figured it out it became one of the most useful and powerful techniques for games. Its especially useful for helping to decouple classes while allowing for messaging.
Delegates - Simply a container for a function that can be used as a variable.
Events - Allows you to specify a delegate that gets called when some event in your code is triggered.
Overview
--------
Objects that want to listen for a specific event can do so by registering as a listener, and when that event is trigged, all the listeners will have their listening function directly called. As many listeners can be registered to each delegate as you want and (heres the best part) each listener can call its own different function from the same event call.
This means if say you have a GUI, another unit and a Controller that are all listening for the same event (eg UnitSpawned), each one can react differently. The GUI may need to update itself, the other unit maybe check distance and the Controller may do something else.
Uses:
-----
The most useful thing I've used them for is to encapsulate my InputController and separate it from all the scripts that might be listening for Input. They can then individually subscribe to listen if the input is triggered without requiring a direct connection. Games are often highly emergent and I sometimes feel enforcing hierarchies or fixed communication channels is a non-intuitive way to structure a world. This lets remote functions on objects get called directly without needing hardcoded references, resorting to Find, or broadcasting (which are all kind of sloppy and clutter your code).
Its a concept worth understanding and once you wrap your head around it, you will wonder how you got by without it.
Events and Delegates were something I struggled with when I was first learning how they worked. Once I figured it out it became one of the most useful and powerful techniques for games. Its especially useful for helping to decouple classes while allowing for messaging.
Code Examples:
---------------
// Event Handler/ Event Manager
// 1 & 2 are same script eg DelegatesAndEvents.cs
1. Define delegates and events
---------------------------------
// just definition of what the event looks like/arguments
// a. Define Delegate **
public delegate void NameOfDelegate ( GameObject unit)
// b. Define Event **
public static event NameOfDelegate onUnitSpawn;
public static event NameOfDelegate onUnitDestroy;
2. // trigger events
--------------------
// This is the same script as #1
public static void NewUnitCreated(GameObject unit)
{
// does this delegate have at least one subscriber?
// should always check that the delegate actually points to something
if(onUnitSpawn != null){ // lighting bolt icon means event
onUnitSpawn(unit);
}
// this calls the function in all listeners
// That list of all listener functions is called delegate invocation list
// when this call is made, all listeners subscribed will call their onUnitSpawn(unit) functions, even though the functions may be completely different ( as long as all the parameter lists are the same as defined in the Delegate )
// you can have as many subscribers as you'd like subscribed to each event
// Heres another Event that uses onUnitDestroy
public static void UnitDeath (GameObject unit){
if(onUnitDestroy != null){
onUnitDestroy(unit);
}
}
3. Subscribe GameObjects To Events
---------------------------------------
Separate Scripts that subscribe want to listen for events.
Eg. GUI, HealthManager, Overlord, Other units - Anything that needs to listen for events
// There can be many different scripts that subscribe to each event as long as they use the same calling structure and arguments
// a. Subscribe object to listen to Event**
// anytime this event (onUnitSpawn) fires, call this method locally (NewUnitCreated)
void OnEnable(){
DelegatesAndEvents.onUnitSpawn += this.NewUnitCreated;
}
// you don't need to type out arguments because the delegate defines which arguments you need
// eg. this.NewUnitCreated <- doesnt need () or arguments, must match delegate definition in the Event Manager
// Unsubscribe event
void OnDisable(){
DelegatesAndEvents.onUnitSpawn -= this.NewUnitCreated;
}
// b. Define the function that the subscriber will execute. **
// can be different for each subscribing script as long as the name and argument list match.
// create the local function that will be called when the event is triggered
public void NewUnitCreated(GameObject unit){
// do stuff, update self etc
// assign stuff to unit,
// create gui etc
}
// each subscriber will react in its own way & you can have as many subscribers you want.
eg. So a UnitManager, GUIManager and OtherUnit can all subscribe to the same delegate event but can call different functions when the event is triggered so long as the function signature matches (eg the arguments match the delegate definition)
Overview Scripts
public class DelegatesAndEvents : MonoBehaviour{
// i. Define Delegate
public delegate void NameOfDelegate ( GameObject unit)
// ii. define events
public static event NameOfDelegate onUnitSpawn;
public static event NameOfDelegate onUnitDestroy;
// 2 - doesn't need to be in its own function, but good practice
public static void NewUnitCreated(GameObject unit)
{
// does this delegate have at least one subscriber?
if(onUnitSpawn != null){
onUnitSpawn(unit);
}
}
// Heres another Event that uses onUnitDestroy
public static void UnitDeath (GameObject unit){
if(onUnitDestroy != null){
onUnitDestroy(unit);
}
}
}
public class GUIManager : MonoBehaviour{
// subscribe to event
void Start(){
DelegatesAndEvents.onUnitSpawn += this.NewUnitCreated;
}
// de-subscribe to event
void OnDisable(){
DelegatesAndEvents.onUnitSpawn -= this.NewUnitCreated;
}
// define method to be called - signature needs to match delegate signature
public void NewUnitCreated(GameObject unit){
// create gui of healthbar for unit etc
}
}
// another subscribing class
public class UnitManager : MonoBehaviour{
// subscribe to event
void Start(){
// note this calls the Class, not the delegate name
DelegatesAndEvents.onUnitSpawn += this.NewUnitCreated;
}
// de-subscribe to event
void OnDisable(){
DelegatesAndEvents.onUnitSpawn -= this.NewUnitCreated;
}
// define method to be called - signature needs to match delegate signature
public void NewUnitCreated(GameObject unit){
// do something else to the same unit on the same event call
eg . unitCount ++;
}
}
Additional Resources
--------------------
This was a very good, clear explanation for Unity
https://www.youtube.com/watch?v=ihIOVj9t0_E
Very Good, 1:09 explantation of Delegates, Event Callbacks and Lambda Expressions. Its working on C# in VS and isn't unity specific but was the most clear & helpful explanation I found.
https://www.youtube.com/watch?v=8e2GEFNctwQ
Unity's own explanation
https://unity3d.com/learn/tutorials/modules/intermediate/scripting/events
Good Explanation, not as clear code
https://www.youtube.com/watch?v=N2zdwKIsXJs
Good example, poor explanation of what and why
https://www.youtube.com/watch?v=ihIOVj9t0_E
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment