First, let's talk about the use case.
I'm building a game where there's a freeze action. When the game is in the freeze mode, I want to notify other game objects. So, they can act accordingly.
Check this demo:
That's where c# delegates come handy.
Event Manager
Usually, you need to have a place to register events. So, other game objects can register and listen to events. In my app, we have a class called GameConfig like this:
(There are more code in this class, but I removed them for clarity)
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class GameConfig : MonoBehaviour
{
public delegate void FreezeChangeHandler(bool isFreezed);
private FreezeChangeHandler freezeHandlers;
public static GameConfig current;
void Start()
{
GameConfig.current = this;
}
// Update is called once per frame
void Update()
{
}
public void OnFreezeChange(FreezeChangeHandler e)
{
freezeHandlers += e;
}
public void OffFreezeChange(FreezeChangeHandler e)
{
if (freezeHandlers == null) return;
freezeHandlers -= e;
}
public void Freeze()
{
freezeHandlers?.Invoke(true);
}
public void UnFreeze()
{
freezeHandlers?.Invoke(false);
}
}
It seems like a lot, but let me explain each of these in detail.
public delegate void FreezeChangeHandler(bool isFreezed);
Here we are defining a delegate. It's a custom type for a function signature. In this case, we define a delegate for a function that accepts a boolean and returns nothing.
private FreezeChangeHandler freezeHandlers;
Here we defined a variable for keeping handlers(function) of our delegate. If you didn't get what this will do, don't worry. You will understand in a bit.
public void OnFreezeChange(FreezeChangeHandler e)
{
freezeHandlers += e;
}
This is a public function in our class, which other games objects register handlers. By doing that, they can get notified when there's a change in our app's freeze state.
See. The first argument of this function is our delegate. So, we can call this function with a function as the argument.
(We can see that in a bit)
public void OffFreezeChange(FreezeChangeHandler e)
{
if (freezeHandlers == null) return;
freezeHandlers -= e;
}
This is similar to the previous one, but for removing the handler. Here, we need to check for freezeHandlers
to be not null because it cannot remove anything if there are no such items inside it.
public void Freeze()
{
freezeHandlers?.Invoke(true);
}
public void UnFreeze()
{
freezeHandlers?.Invoke(false);
}
Finally, we have two functions to notify (or call) these handlers. In my app, we have two functions like this. But in your app, it could be based on some user input or similar.
What you need to know is how we can call these handlers like this:
reezeHandlers?.Invoke(true);
Register Handler
Now we can register a handler for this delegate like this:
using System;
using System.Collections;
using UnityEngine;
public class Drop : MonoBehaviour
{
void Start()
{
GameConfig.current.OnFreezeChange(WithFreezeChange);
}
private void OnDestroy()
{
GameConfig.current.OffFreezeChange(WithFreezeChange);
}
private void WithFreezeChange(bool isFreezed)
{
// Do something with the state change
}
}
Let me explain each of these code blocks:
private void WithFreezeChange(bool isFreezed)
{
// Do something with the state change
}
The above function is our handler for the event. It has a signature that is similar to our delegate; it accepts a boolean & returns nothing.
void Start()
{
GameConfig.current.OnFreezeChange(WithFreezeChange);
}
Then we will register our handler by getting an instance of our game config.
private void OnDestroy()
{
GameConfig.current.OffFreezeChange(WithFreezeChange);
}
We also need to remove the handler when the game object is destroying. Otherwise, it will lead to errors and memory issues.
Example
Thanks for reading up to here 🙏.
Have a look at this example game to see this in practice.
Top comments (0)