9

I am trying to use the event system in Unity (the C# way), but I am having problems to implement it.

Most of the examples, show one class, where you define the handler; then you write in the same class, the function that match the signature of the handler, and you write the events as static

public class EventExample : MonoBehaviour
{
    public delegate void ExampleEventHandler();
    public static event ExampleEventHandler OneDayPassed;

    public static void NextTurn()
    {
        // do stuff then send event
        if (OneDayPassed != null)
            OneDayPassed();
    }
}

Then in another class, you subscribe to the events, creating a function that actually do something

public class EntityWatcher: MonoBehaviour
{
    void Start()
    {
        EventExample.OneDayPassed += this.PrepareNextDay;
    }

    public void PrepareNextDay()
    {
        // Do other stuff that happen after the day is done

    }
}

So far no problems, but I am not sure how do I design this, so any GameObject of a particular type, will subscribe to this event. For example, if you have a staff category of GO, that is working 8 to 6, and you instantiate them at runtime; should I subscribe in the main class of this category, or should I create a script that I attach to the Game Object prefab, that subscribe to the event?

The objective is that all the staff members that should do a 8 to 6 shift at the sport center, know when the "day is done" event fire up, but I don't want to subscribe every single prefab that I instantiate.

From my understanding, I should attach a script with the needed code on the prefab, but I can't find a practical example that show if that is in fact the way to do it.

  • Hi Newb'z. This is all totally and completely wrong. These day syou just use `UnityEvent`. You do not use and realistically cannot use the "old fashioned" events from a decade ago. – Fattie Mar 27 '16 at 15:49
  • So it is better to rely on something used only in Unity, Vs something that is part of the language itself? –  Mar 27 '16 at 23:34
  • Hi @newbiez. Yes, that's absolutely correct. – Fattie Mar 28 '16 at 00:02
  • You should understand that wen you are using Unity, you are using an *extreme distortion* of conventional programming. It is not an OO system, it is ECS. Consider this recent question from myself, http://stackoverflow.com/questions/36251078/in-unity-how-does-unity-magically-call-all-interfaces/ unity has these "interfaces" that are actually completely haywire and the opposite of "interface" in c#. – Fattie Mar 28 '16 at 00:05
  • I don't get this. Everywhere else I've looked says native C# events are superior to UnityEvent, even here on https://stackoverflow.com/questions/44734580/why-choose-unityevent-over-native-c-sharp-events and then here is a comparison showing native C# events are better here: https://jacksondunstan.com/articles/3335 but strangely this question and comments and all the answers are now saying UnityEvent is better? I'm utterly confused. – user4779 Sep 24 '19 at 07:03

2 Answers2

43

You must use UnityEvent.

public UnityEvent whoa;

It is dead easy.

Make a script BigScript.cs

using UnityEngine;
using System.Collections;
using UnityEngine.Events;

public class BigScript:MonoBehaviour
{
    [Header("Here's a cool event! Drag anything here!")]
    public UnityEvent whoa;
}

Put it on a game object. Now look at it in the Inspector.

You will see the "whoa" event.

Simply drag your other scripts to there, to make something happen, on those other scripts, when "whoa" happens.

enter image description here

It's that simple. To call the event in BigScript, it is just

    [Header("Here's a cool event! Drag anything here!")]
    public UnityEvent whoa;
    
    private void YourFunction()
    {
        whoa.Invoke();
    }

In rare cases you may need to add a listener via code rather than simply dragging it in the Editor. This is trivial:

whoa.AddListener(ScreenMaybeChanged);

(Normally you should never have to do that. Simply drag to connect. I only mention this for completeness.)


That's all there is to it.

Be aware of out of date example code regarding this topic on the internet.


The above shows how to connect simple functions that have no argument.

If you do need an argument:

Here is an example where the function has ONE FLOAT argument:

Simply add THIS CODE at the top of the file:

[System.Serializable] public class _UnityEventFloat:UnityEvent<float> {}

then proceed as normal. It's that easy.

// ...
using UnityEngine.Events;

// add this magic line of code up top...
[System.Serializable] public class _UnityEventFloat:UnityEvent<float> {}

public class SomeThingHappens : MonoBehaviour
{
    // now proceed as usual:
    public _UnityEventFloat changedLength;
    
    void ProcessValues(float v)
    {
        // ...
        changedLength.Invoke(1.4455f);
    }
}

When you drag from your other function to the Editor slot on this function:

Be certain to use the section - "Dynamic float".

enter image description here

(Confusingly your function will also be listed in the "Static Parameters" section! That is a huge gotchya in Unity!)

Fattie
  • 27,874
  • 70
  • 431
  • 719
  • Thanks Joe, this is vastly simplier than using the standard C# Delegates and Events system. My only worry is that once you get used to this, you will loose the standard C# way to do things...I do write code for both Unity applications and pure C# applications, so my "to-go" approach is usually to use whatever C# offer natively. I assume that Unity approach is as performant as using regular Delegates and Events in C#; thanks! –  Mar 28 '16 at 00:31
  • 2
    hi newbiez, conventional c# events *do not work* in the Unity context since it is an ECS system. *For that reason* Unity created the (outstanding) UnityEvent system. Regarding the fact that you work on multiple systems - no big deal. You have to be expert at both. That's life! – Fattie Mar 28 '16 at 03:02
  • I see; I did implement my system using regular C# code with Events and Delegates, but this is much easier, and comform to the ECS model, like everything else in Unity. Indeed you must be a jack of all trade :) –  Mar 28 '16 at 06:17
  • Question: What I would like to understand is how to specify the values for the arguments in the Inspector when using a derived `UnityEvent` type (e.g, `public class CustomEvent:UnityEvent`). When using this, the Inspector understand the signature (string,float), allows selection of the function to invoke within the target script, but does not allow you to specify values for these arguments within the Inspector. This ability is available when binding a stock `UnityEvent` to a function that takes a `string` argument. Perhaps it is not possible without custom editing code? – Randy Larson May 11 '19 at 19:40
  • @RandyLarson , indeed, I think very simply "they don't do that". Just as you say, it only works in the simple "one string" case. I'm too lazy to open Unity on the weekend, but maybe something like this helps ?? http://answers.unity.com/answers/1230225/view.html cheers! – Fattie May 11 '19 at 19:43
  • agreed. I think path is down the custom editor trail. – Randy Larson May 12 '19 at 01:44
  • You stated "To be clear: never do that - simply drag to connect. I only mention it for completeness." I only use Unity as a hobby. My first instinct was that I would want to add event listeners via code for prefabs that are instantiated via code. I am guessing you just apply listeners to the prefab prior to cloning it? So, in reality, is there ever a time where you think it would be a good idea to add a listener via code? – PaulBinder Jun 04 '19 at 17:33
  • 1
    Howdy @PaulBinder (1) sure, there are cases where you would do it in code (2) I was answering above in the context of getting a beginner going: there had been some confusion that this was something you "do in code"; whereas particularly *in the actual example under discussion*, and almost always, it has "nothing to do" with code, you just click it in the inspector there, so i was trying to clear that up. ( (3) regarding your specific case, TBH I'm not totally clear what you're doing, so I don't know! :) {natch, you could ask another question on here} Cheers! – Fattie Jun 04 '19 at 18:01
  • Thanks for the quick response Fattie. Just making sure there was not some sort of standard/best practice that I was missing! – PaulBinder Jun 04 '19 at 19:56
  • Why "never do that " for AddListener? – DataGreed Aug 08 '19 at 12:43
  • @DataGreed , paul (just above) had the identical question .. note the last few comments! – Fattie Aug 08 '19 at 14:52
  • 1
    The whole purpose of using events is to decouple code as much as possible and to have a robust system where you will have less dependencies. Adding game objects via the inspector is the easy way out but there are better, elegant and sturdy ways to do it. Look at the tutorials by Sebastian Lague on Youtube. – emorphus Mar 17 '20 at 04:52
  • (Completely irrelevant to an ECS system) – Fattie Oct 27 '20 at 16:33
2

Don't worry too much about the number of subscribers if you are only talking about a few dozens. Yes, once you get into the hundreds or thousands it might be a good idea to optimize this, but even then. First rule of optimization: don't optimize.

So: just have every instance subscribe to the event and be done with it.

Thomas Hilbert
  • 3,559
  • 2
  • 13
  • 33
  • Agree; since I didn't use Unity before for this kind of things, I wanted to be sure that I am doing it in the "right" way. I do not have too many events, but I have hundreds of subscribed entities to these events, since all the entities in my application, depend from when certain cycles start and end (theya re all instances thou, so that should clear with Unity easily). –  Mar 28 '16 at 00:33