How & why to use Static Events in Unity3D

แชร์
ฝัง
  • เผยแพร่เมื่อ 18 ต.ค. 2024
  • Check out the Course: bit.ly/3i7lLtH
    -------
    Static events can simplify and help decouple your code. You can use them to register once and handle callbacks for a bunch of objects (instead of registering for each one).
    More Info: unity3d.college
    Join the group: unity3d.group
    Patreon: / unity3dcollege

ความคิดเห็น • 86

  • @shahroonfarooqi6403
    @shahroonfarooqi6403 6 ปีที่แล้ว +141

    vote for sub-component events

    • @robosergTV
      @robosergTV 3 ปีที่แล้ว

      did he do such video?

  • @duovisj
    @duovisj 6 ปีที่แล้ว +89

    Would love to see how sub-components would interact with the events :)

    • @SunnyApples
      @SunnyApples 6 ปีที่แล้ว +7

      Me to!
      I would also love to hear about how Unity native events compare to these C# ones.

    • @shindao6
      @shindao6 6 ปีที่แล้ว +4

      The unity native events are slow, don't use them

  • @dynasticc
    @dynasticc 4 ปีที่แล้ว +7

    I always felt like I was doing something wrong when I would do something like you originally showed but I never could figure out why, or another way. This feels way more efficient, thank you!

  • @robosergTV
    @robosergTV 3 ปีที่แล้ว +4

    your event example is still tightly coupled since you define an event by name. So both objects are still dependent on having to use the same name for the event. You literally use "ClickableBox" in the awake() of your particle system, both objects are still coupled.

  • @harrysanders818
    @harrysanders818 5 ปีที่แล้ว

    Your videos are so super useful and to the point for people starting their joruney towards more intermediate and advanced concepts, trying to tighten their understanding. Thanks from the heart for doing what you are doing!

  • @JoeGeorge319
    @JoeGeorge319 3 ปีที่แล้ว

    I was looking for your head in the thumbnail as a reference to come back to and almost lost this video, that is all. Thank you for the information here. Also sub-component events would be pretty fly

  • @insaneduane
    @insaneduane 3 ปีที่แล้ว

    Learning about sub-components would be a good thing. Thank you for all your videos.

  • @uzimonkey
    @uzimonkey 6 ปีที่แล้ว +12

    I do something similar. I have a whole bunch of event structs prefixed with Ev, so I'll have an EvPlayerDamaged struct that has all the information about that event including a reference to the player, the thing that damaged it, whether it killed the player, the amount of damage, etc. I then have a templated Event class with the actual event in it, so Event with a small API to add event handlers, remove event handlers and invoke the event.
    I like it this way because the struct defines an API but allows me to add fields to the event without having to refactor all the event listeners. If they were parameters as in your code I'd then have to go update every single listener. Also, it cuts down on repetition since all the events are handled with one Event class.

    • @Unity3dCollege
      @Unity3dCollege  6 ปีที่แล้ว +1

      Sounds interesting, would love to check that out some time if you happen to have an example you can share :)

    • @williamleebuckley
      @williamleebuckley 6 ปีที่แล้ว +2

      Seconded, would love to see that. I've been using SO events for a lot of the functionality in a turn-based multi-unit prototype, and finding the repetition and refactoring an issue, and can't find a way to make the whole workflow generic/abstracted.

    • @uzimonkey
      @uzimonkey 6 ปีที่แล้ว +7

      Well the actual implementation is like ~10 lines of code and very similar to what I've posted below.
      As for your SO problem, you can cut out the repetition by using a combination of the struct instead of parameters and inheritance.
      pastebin.com/q44qWRbq
      pastebin.com/TBwXYQE1

  • @Hennadii_S
    @Hennadii_S ปีที่แล้ว

    Beautiful video! I was really needed in it! Makes lot of things much easier to implement and giving new ways tp use such greate tool as events!
    Thank You for Your job!

  • @brief9824
    @brief9824 3 ปีที่แล้ว +5

    Thank you for the video. Really helpful. Question: What are pros and cons of Event System as a separate class with all the events vs events scattered around in scripts?

  • @ravanin
    @ravanin 6 ปีที่แล้ว +16

    Do you have a playlist on decoupling? Its something that not many seem to be doing

  • @QuietPenguinGaming
    @QuietPenguinGaming 2 ปีที่แล้ว

    This was extremely helpful, thanks Jason!

  • @CoReeYe
    @CoReeYe 6 ปีที่แล้ว +14

    I'm thirsty for a sub-component tutorial.

    • @Adkinsy85
      @Adkinsy85 5 ปีที่แล้ว +2

      💦💦

  • @andresmicalizzi5420
    @andresmicalizzi5420 4 ปีที่แล้ว +1

    A bit late, but a vote for subcomponents and more eventa! Great content man!

  • @behnamrasooli8801
    @behnamrasooli8801 6 ปีที่แล้ว +2

    If you use an event manager which you can find one on assetstore, you don't have to worry about a lot of stuff. Of course, you can write your own event manager, and there is actually a course on this subject on Unity website.

    • @Unity3dCollege
      @Unity3dCollege  6 ปีที่แล้ว +1

      Definitely, gonna do a video on that soon too :)

  • @wholebitmedia
    @wholebitmedia 5 ปีที่แล้ว

    You mentioned singletons in the beginning of this video which has turned into a monster of variable registration for mothed use. Might watch this again to trim the fat using some events/delegates. THX

  • @PerfectlyNormalBeast
    @PerfectlyNormalBeast 4 ปีที่แล้ว

    Quick note for that ray cast. If you don't care about an out param, you can just use underscore:
    CallingAFunction(out _)

  • @karim009
    @karim009 6 ปีที่แล้ว +1

    Thanks for the video! I am interested in the sub components video!

  • @owencoopersfx
    @owencoopersfx 2 ปีที่แล้ว

    What I like to do is make a static class which holds (nearly) all my static events. Then I make static methods in that class which simply invoke the static events with the signatures I want to pass around the data types I need. Then any class can run those static methods to raise the events. I think this works best for things where you’d have otherwise unrelated things reacting to the same game event. Even then in the case that I need to reference the class/object that raised the event, then I just make an argument for GameObject or (that class) and have the raiser pass itself in for the callback functions to grab the reference.

  • @imaginationrabbit
    @imaginationrabbit 6 ปีที่แล้ว

    Wow, this is really useful- thanks for the video!

  • @bentonjustice1218
    @bentonjustice1218 3 ปีที่แล้ว

    Sweet baby Jesus. I was competing in a game jam this weekend and I was like man I really wish they had something like an event that was static that I could pass a this keyword into. Being a native Java developer I thought, “This and static... yeah right.” Went on with a tightly coupled spaghetti code project. C# is duilt bifferent

  • @cachorro25
    @cachorro25 6 ปีที่แล้ว

    Me too. Always thought that events firings were generic by default. Would love to see how to register to specific objects events without much class coupling

  • @SamMJam95
    @SamMJam95 6 ปีที่แล้ว +5

    Pls make tutorial on sub components events

  • @mana20
    @mana20 5 ปีที่แล้ว

    I'd like to see a video handling events on a per instance basis / sub components. That's one of the main issues I have with events and architecture like the scriptable object event system Ryan Hipple showed at his talk.

  • @LimpinJezus
    @LimpinJezus 6 ปีที่แล้ว +1

    Hey Jason, great content as always. Quick question; what, if any difference is there between a standard c# delegate and UnityEvents and is there a real performance difference? It would seem you'd want to prefer UnityEvents so your designers can see all the inter-relations in the inspector, but I defer to the experts.

    • @Unity3dCollege
      @Unity3dCollege  6 ปีที่แล้ว +1

      Sometimes I'll use them, but most of the time, I dont' want designers hooking up events and I want the references in code (so when i search for references i can find them easily). There are some cases where i do use them though, when design is really customizing the game through them, it's just not the case for the majority of games I've built in the past :)

  • @aronbroom7977
    @aronbroom7977 4 ปีที่แล้ว

    This was fantastic! Thanks so much

  • @icamefromspace
    @icamefromspace 6 ปีที่แล้ว

    I'm also interested in the sub components video.

  • @onurtnrkl
    @onurtnrkl 6 ปีที่แล้ว +2

    I use observer pattern in these situations. If we implement observer pattern to this example, we can say ClickableBox is Subject and ParticleControllers are observers.

    • @AlexanderMouse
      @AlexanderMouse 6 ปีที่แล้ว

      Don't you mean the other way around? The ParticleController would be the observer. It wants to observe the ClickableBoxes because it wants to know when they are clicked on. Thus the ClickableBox is the subject which is being observed.

    • @AlexanderMouse
      @AlexanderMouse 6 ปีที่แล้ว

      Also, using events is a way of implementing the observer pattern. So he is also applying the observer pattern in this video.

    • @onurtnrkl
      @onurtnrkl 6 ปีที่แล้ว

      @@AlexanderMouse No, you are wrong. Observers should observe subject and subject should notifity all observers. For example;
      public void RegisterObserver(IObserver observer){ observers.Add(observer);}
      And registering like this from Observers;
      particleController.AddObserver(this);

    • @onurtnrkl
      @onurtnrkl 6 ปีที่แล้ว +1

      @@AlexanderMouse events are 2x slower than interface calls. If there is null check on events it become 3x slower.

    • @AlexanderMouse
      @AlexanderMouse 6 ปีที่แล้ว

      You are correct that observer should observe the subject and that the subject should notify the observers. Where does something happen? It is the ClickableBox that is clicked. It is the ClickableBox that wants to notify others (observers) that it has been clicked, thus it is the subject. The ParticleController wants to be notified about these clicks, thus it is the observer. It is observing the ClickableBox.
      I am not aware of the speed difference between events and interfaces, but events provide more loose coupling than interfaces and thus more flexible code. I prefer using events. Speed has never been any issues with my games, but it's interesting that you say interfaces are faster. I'll look into it. Thanks. :)

  • @gayan1742
    @gayan1742 3 ปีที่แล้ว +1

    This is convenient. But in case we want to reuse the ClickableBox it could cause problems since the event being fired is always the same. And the listener has to check who's the caller.

  • @TsetTsyung
    @TsetTsyung 6 ปีที่แล้ว +1

    Such an awesome video, thank you so much! Another subject that was on my to-research list, lol. XD

    • @mandy1339
      @mandy1339 4 ปีที่แล้ว

      me too. This was made so easy by Jason.

  • @AlexanderZotov
    @AlexanderZotov 5 ปีที่แล้ว

    I wish to give more likes to this video!

  • @mattomwit
    @mattomwit 5 ปีที่แล้ว

    Really good video thank you for taking the time to teach this stuff.

  • @Un4GivNX
    @Un4GivNX 5 ปีที่แล้ว

    I do know about Action and static declaration. I assume that writing:
    Public static Action would work.
    Question: what does the "event" keyword do on top of that?

    • @Un4GivNX
      @Un4GivNX 5 ปีที่แล้ว

      I've found the answer - stackoverflow.com/questions/3028724/why-do-we-need-the-event-keyword-while-defining-events
      "An event is fundamentally like a property - it's a pair of add/remove methods (instead of the get/set of a property). When you declare a field-like event (i.e. one where you don't specify the add/remove bits yourself) a public event is created, and a private backing field. This lets you raise the event privately, but allow public subscription. With a public delegate field, anyone can remove other people's event handlers, raise the event themselves, etc - it's an encapsulation disaster."

  • @ZaCkOX900
    @ZaCkOX900 4 ปีที่แล้ว

    The reason I don't use this is because of consistency, you don't always want to have a static event, register, deregister... for every scenario. It becomes worse of a pain than coupling in some cases.

  • @iamgingerbread6558
    @iamgingerbread6558 ปีที่แล้ว

    Is this more like observer pattern, or singleton pattern because of use of "static"?

  • @phambaoha170
    @phambaoha170 5 ปีที่แล้ว

    Good series technical unity

  • @Maximetinu117
    @Maximetinu117 5 ปีที่แล้ว

    did you finally did a video for sub component events?

  • @frankerzee1095
    @frankerzee1095 6 ปีที่แล้ว

    Thank you so much for this it really helps a lot. What I have been doing is creating singletons that are solely responsible for handling certain events. For example when my player collides with an item, the item class calls an OnItemGet event from the singleton and does various stuff like playing a sound, particles, adding to inventory, etc... Is this a viable solution or should I skip the singleton all together and just stick a static event on my item class? I feel like making a singleton just to handle an event is a bit overengineering...

  • @DePistolero
    @DePistolero 4 ปีที่แล้ว +1

    I had static events and on every level load/restart I get into problems because of not de-registering them, like things not loading properly or null reference exeptions. But with instance events no problems, no need to de-register them. When I de-register statics onDisable, it is all good, if not than it is not working on level restart....

  • @ethansk3613
    @ethansk3613 4 ปีที่แล้ว +1

    This causes memory leaks if you do not deregister the subscriber. Also even if you did, it would cause memory leaks on leaving the scene and the ondisable would be called in arbitrary order, and C# wouldn't garbage collect as there is still a reference.

    • @victoraurelius5334
      @victoraurelius5334 3 ปีที่แล้ว +1

      if you unsubscribe in OnDisable(), why would it cause memory leaks on a scene change? Scene change would mean, that the ParticleController gets destroyed. Right before that, Unity calls OnDisable on the GameObject, so everything should be fine?

  • @angeldiaz7554
    @angeldiaz7554 5 ปีที่แล้ว

    This is very helpful! Thank you very much!

  • @jerrettfarmer
    @jerrettfarmer 3 ปีที่แล้ว

    Thank you!

  • @jacobester3846
    @jacobester3846 3 ปีที่แล้ว

    Thanks, so do you not need to deregister the static events?

  • @alexslavski5056
    @alexslavski5056 5 ปีที่แล้ว

    It would be nice, if you included a link to someplace that explains in a more beginner-friendly way what those events are and how they work. At the moment this tutorial is only good for people who already know what they are.

  • @pythonxz
    @pythonxz 2 ปีที่แล้ว

    I like using static events for tab classes.

  • @MrDeleoAndre
    @MrDeleoAndre 3 ปีที่แล้ว

    makes sense from a coder perspective however you are limited to having same behavior for all boxes and same type :)

  • @nikitagoncharuk6367
    @nikitagoncharuk6367 6 ปีที่แล้ว +1

    I think it's too wasteful to have an Update method in every ClickableBox that creates a ray and checks if we hit the box. Can you explain this in more detail?

    • @beardordie5308
      @beardordie5308 6 ปีที่แล้ว +1

      You could just have one gameObject with an update method checking input and raycasting, then use this very same static event pattern for the clickable boxes to register for the click event. That would reduce the code execution. But not every demo has to be scripted at 100% performance to be useful for learning. It was a good observation however.

  • @hsck98
    @hsck98 5 ปีที่แล้ว

    Could someone try to give some advice on what might be wrong in my case.
    For easier understanding ill use the example used in this video.
    I currently have a static event which should trigger whenever a box is CREATED (there are 12 boxes, so the event should trigger 12 times)
    However, only 3 of the 12 boxes are instantiated.
    One observation is that the event DOES trigger when I create a box after the initial loading (eg if I duplicate one of the boxes, the event triggers). I assume this means that its got something to do with the initial loading but I cannot seem to understand why. Someone help please?

  • @milovannovakovic2273
    @milovannovakovic2273 6 ปีที่แล้ว

    Please do the sub-object video. Thank you.

  • @a45860
    @a45860 4 ปีที่แล้ว

    So would it be smart/okay to decouple player scripts so I can have like animations, controller, stats, weapons, combat in different scripts and call each other with non static events? If multiple players they only listen to there own events right?

    • @klarnorbert
      @klarnorbert 4 ปีที่แล้ว

      If you have all those script components on one gameobject, it doesn't make any sense. But for example, you set up an event on Player gameobject, and if the Player loses health, it fires that event, and your UI(which is showing Player's health), it can subsribe to that event, and update the UI. This is just a simple example.

  • @PS-vj6jz
    @PS-vj6jz 2 ปีที่แล้ว

    Perfect!!!

  • @janosdomboroczki8456
    @janosdomboroczki8456 6 ปีที่แล้ว

    I would like to see how does it work with sub compnents.

  • @jakubpyszczak523
    @jakubpyszczak523 6 ปีที่แล้ว +1

    Why do You call Input.GetMouseButtonDown(0) on every ClickableBox? I think it's not optimal, isn't it? Instead I would create singleton that is called once (not for every clickableObject). Or maybe I'm wrong and You create this on purpose?

    • @scottcourtney8581
      @scottcourtney8581 6 ปีที่แล้ว

      I think he took the easy path for input management because it isn't the main topic of this video, but I do agree with you. I typically use the pattern of having some kind of an input manager component where I centralize *all* of my button and key handling, then send out C# events from there to other code. The one place that pattern doesn't work too well is if you need to query the state of a button or key, rather than an up or down transition. Events also aren't the best choice (IMO) for reading analog values.

  • @jamestacular
    @jamestacular 4 ปีที่แล้ว

    Would you say this is basically Observer pattern?

  • @UmbrAtrox
    @UmbrAtrox 6 ปีที่แล้ว +2

    Thank you! I have a doubt
    If you delete a cube, does the subscription continue in memory?
    (I'm just learning about events and I've read that you should always cancel a subscription but in this example, deleting a cube does not throw you errors)

  • @halivudestevez2
    @halivudestevez2 2 ปีที่แล้ว

    wow!

  • @fluchan233
    @fluchan233 6 ปีที่แล้ว

    Nice video. However you should mention necessity of unsubscribing from static events. Without unsubscribing Unity throws bunch of errors after runtime scene reset.

    • @the_pachu4953
      @the_pachu4953 6 ปีที่แล้ว

      yeah, is necessary make a clean when you change or reset the scene, the subscriptions on this events are still in memory. Same with observable subscriptions.

  • @lonaur
    @lonaur 6 ปีที่แล้ว

    Hi Jason,
    I've researched about statics two weeks ago and found this thread with the info to not use an empty delegate:
    forum.unity.com/threads/how-to-use-delegates-like-a-boss.312800/#post-2079197
    What do you think?

    • @Unity3dCollege
      @Unity3dCollege  6 ปีที่แล้ว

      If the project is in .net 4.5+ I don't use them, and instead use a ?.Invoke(). But in older framework versions I still use them every time just because it simplifies the code.
      As for serialization, perhaps that could be an issue (not one I've ever run into though), but generally I wouldn't want to serialize a class that has behavior like this.. That serialization would happen on a class or struct that has data only, no behavior. (in the original tutorial where he talks about using them, it's with an event anyway and wouldn't get serialized)
      Also if you're ever in a situation where you really need to do that, you can use attributes to prevent things from being serialized like this - stackoverflow.com/questions/10816949/serialization-of-a-class-with-events
      But again, I can't think of a case where I'd want an event serialized.. I'm open to suggestions or possible use cases though if anyone has some?

    • @tonychristney2728
      @tonychristney2728 3 ปีที่แล้ว

      @@Unity3dCollege I think the issues with the empty delegate are subtle, but eventually they will come back to haunt you. First, even though you have an empty delegate, you still are paying the cost of the method call on that. Yeah, it's tiny, but it's still more expensive than a null check. Second, there is a life cycle issue related to garbage collection. If the controller class goes out of scope, the static event list is retained, along with all of the references to potentially destroyed objects on the unity side. Then another instance of the controller class gets created, maybe during another scene load, but all those references are still there and your game is broken.
      The solution for me is to have the null check (it's usually only in the one place - if not then a private "Fire" method). When the "owner" of the event is destroyed, set the event list to null and all those dangling references are deleted, even if the observers have not been destroyed or otherwise deregistered yet. This is in addition to the necessity of having a matching -= for every += in your event handlers.
      This also skips over what, for me, is the biggest problem with static events like this. If any delegate throws an exception, none of the other delegates are fired. In some cases this is fine, but in other cases it's just a bug that can stall a whole team while it gets fixed. It would be worth showing people how to handle that situation to make a more robust event publisher.
      Last issue that I see all the time is naming. People seem to love calling their events "OnFoo". But the C# convention recommends against that. The event should be named "Foo" and the delegates attached to it should be named "OnFoo". Otherwise you get things like "source.OnFoo += OnFoo" which just looks weird to me.

  • @selfreference2
    @selfreference2 6 ปีที่แล้ว

    ECS seems better, but this is lower overhead.