Тёмный
No video :(

Learn to Build an Advanced Event Bus | Unity Architecture 

git-amend
Подписаться 15 тыс.
Просмотров 22 тыс.
50% 1

Опубликовано:

 

5 сен 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 233   
@git-amend
@git-amend 10 месяцев назад
Beginner or Advanced - I hope you learn something new about Unity and/or C# programming today! Let me know what you think about bootstrapping custom services before game load!
@jkka60
@jkka60 2 месяца назад
@git-amend What's the use of the Utils class?
@git-amend
@git-amend 2 месяца назад
​@@jkka60 It ensures that event buses are set up properly and can be cleared when exiting Play Mode in the Editor. There are detailed explanations for each method in the code comments if you check the repository.
@forcedtotalk7585
@forcedtotalk7585 10 месяцев назад
It's great that someone is doing tutorials for developers who are already way past the beginner stage. Sorely underrepresented section on youtube. Keep it up!
@git-amend
@git-amend 10 месяцев назад
Thank you so much, more to come!
@nateHERE
@nateHERE 8 месяцев назад
Exactly, I have a problem with finding intermediate and advanced tutorials. Keep it up bro!
@artemstolyga6829
@artemstolyga6829 8 месяцев назад
I agree! Thank you so much, this is exactly what I was looking for. Keep up the good work! Any other RU-vid channels that have similar content? 🙏
@Pygon2
@Pygon2 10 месяцев назад
I love the fact that you take the extra steps to make a more maintainable solution, rather than so many other tutorials that will take the easiest to understand (and least maintainable) approach. These are the types of tutorials developers need, rather than ones that end with an unspoken hand wave of "and people can figure out the rest". Setting "game" development aside, we aren't teaching people to be good programmers if we always stop the tutorials at a basic level. Thanks for all the effort you put in and for elevating the tutorial space.
@git-amend
@git-amend 10 месяцев назад
Thank you very much, I really appreciate that.
@anveio
@anveio 10 дней назад
As a 6yoe FAANG engineer that's implemented Event Buses in various languages (notably have not done so in C#) this entire channel is a freaking goldmine, cumulatively worth at least 5 figures to me personally and possibly millions to my company. I can't thank you enough.
@git-amend
@git-amend 10 дней назад
Awesome, that's very nice to hear! Thank you!
@pickgliss2498
@pickgliss2498 3 месяца назад
For reading the description of this video , finally, I know the difference between the Event bus and the Event Channel.
@git-amend
@git-amend 3 месяца назад
Awesome, glad to hear it.
@dustintaub
@dustintaub 10 месяцев назад
I always learn new things with your videos. Suggestion for future topic, can you discuss/compare Event Buses, Event Channels, Observer Patterns, and C# EventHandlers (and Actions). There seems to be a lot of overlap with these topics and I'm a little confused on when you would use one over the other. I think in the end, it's all about decoupling code but I want to wrap my head around the big picture. Love your work, thanks!
@git-amend
@git-amend 10 месяцев назад
Great suggestion! I'll take note of that. Thank you!
@gaffeOS
@gaffeOS 6 месяцев назад
As others have commented, desperately needed these levels of advanced tutorials. Being entirely self-taught it's easy to go too long without understanding and using these patterns, this has helped a lot. Thanks!
@git-amend
@git-amend 6 месяцев назад
You're very welcome!
@forbiddenbox
@forbiddenbox 10 месяцев назад
I'd like to point out that Unity already does this for you with UnityEvent and UnityEvent this video is for people that are very familiar with unity already and would like to have more control over their event system, also doing it this way teaches you C# so that when you try doing things outside of Unity that use C# you don't have to relearn using events
@Broudy001
@Broudy001 10 месяцев назад
This looks really powerful, I'll have to watch it a few times to get my head around it.
@git-amend
@git-amend 10 месяцев назад
Sounds good! I know you like systems, so have fun :)
@falricthesleeping9717
@falricthesleeping9717 5 месяцев назад
My mind was blown how you implemented this thing, suffice to say playing with this system and seeing when it works best for this system is going to be a challenge I'd love to take, and I only watched one of your videos, gonna watch everything you make from now on mate, you're a gem
@git-amend
@git-amend 5 месяцев назад
Thanks, glad to hear that!
@nankinink
@nankinink 10 месяцев назад
This system looks incredible! I did the same with Scriptable Objects, following the data-oriented approach but tbh, still kinda sucks having to manage all the files and create a new type for each event. Yours much more cleaner and easier to work with. Also, I suggest you keep this simpler version separated from the one with more features! It's easier to expand the code when things are still simple, then we can add features as the project requires
@git-amend
@git-amend 10 месяцев назад
I like the Scriptable Objects approach in that it makes it easy for your designers to add their own events. Thanks for your comment!
@TChrisBaker
@TChrisBaker 8 месяцев назад
I was using Scriptable Objects too but I like this so much more
@msmatheusaugusto1
@msmatheusaugusto1 10 месяцев назад
Your channel was a very good find that I found, it is difficult to find more advanced content about design patterns, and more robust methodologies for Unity here on RU-vid. Thank you very much for sharing your content!
@git-amend
@git-amend 10 месяцев назад
Awesome, thank you!
@friedcrumpets
@friedcrumpets 10 месяцев назад
Trumps my event bus completely and you've made it a public Repo thank you :) A lot of interesting things to note here that I haven't thought of before. My favourite being the idea that static systems are actually hidden behind the creation of objects rather than referencing them directly in scripts. It looks a heck of a lot cleaner to read and more organised too. Also I had no idea Rider had released an AI assistant. I'm now on the waiting list, can't wait for that. As always great video, keep them coming 🥳Learning a lot each video; it's nice to see some more intermediate/advanced tutorials than the usual beginners guides.
@git-amend
@git-amend 10 месяцев назад
Thank you for your comment! I've been very impressed by the JetBrains AI Assistant, I think you'll like it.
@baselpro5228
@baselpro5228 10 месяцев назад
I still didn't watch the video yet but i already know is going to be a banger. Thx for the videos.
@git-amend
@git-amend 10 месяцев назад
Haha thanks! I appreciate it!
@Sparklmonkey
@Sparklmonkey 8 месяцев назад
THank you so much for this video!!! I've been trying to find an elegant way to manage interactions in my card game. I've tried UnityEvents, Actions, Delegates, and direct references. But this is by far the cleanest method I've found and is making my code look so much cleaner. Plus it's letting me optimize the rest of my code better. This tutorial is absolutely amazing! Awesome explanations and examples.
@git-amend
@git-amend 8 месяцев назад
You're so welcome! I really enjoy reading comments like yours!
@nicholaspankuch6405
@nicholaspankuch6405 7 месяцев назад
Great tutorial! I just implemented this in my Monogame project; barely changed a thing! I've slightly modified it to allow it to drive my State Machine pattern as well! All of that to say, great tutorial!
@git-amend
@git-amend 7 месяцев назад
Awesome! Very cool.
@stevehamilton321
@stevehamilton321 10 месяцев назад
Wow... I have no choice but to subscribe : ) Currently looking to refactor my "move fast and break things" event system in my game. This was awesome!
@git-amend
@git-amend 10 месяцев назад
Welcome aboard!
@xSoNiCcRaCkErSx
@xSoNiCcRaCkErSx 10 месяцев назад
Not sure how you don't have more subscribers, this is one of the best Unity hacks channel I've ever seen. Your event bus destroys my messenger I made to de-couple and takes full advantage of many of the new C# features. When we started our project Unity only supported .NET 3.5 so a lot of our code base doesn't use any of the shortcuts and advanced features that are now available and I haven't bothered looking at it to keep things consistent. After seeing this video it is really making me want to re-do and switch things around to take advantage of them, lol.
@git-amend
@git-amend 10 месяцев назад
Thanks for the kind words!
@AramisGameStudio
@AramisGameStudio 10 месяцев назад
Dude this is incredible! I have no idea what you're doing, but I'll find out eventually :D
@git-amend
@git-amend 10 месяцев назад
It may take a couple of watches, but you got this!
@LimitedInput
@LimitedInput 10 месяцев назад
Def a lot of things that are new to me. I need to read up some more to fully understand the code.
@git-amend
@git-amend 10 месяцев назад
Awesome, glad to introduce some new ideas!
@NotJustUnity
@NotJustUnity 10 месяцев назад
Hi, I just want you to know that I learned so much from this video. There are some methods I have not known their existence ! Thanks for the video !
@git-amend
@git-amend 10 месяцев назад
You are welcome!
@NotJustUnity
@NotJustUnity 9 месяцев назад
@@git-amend tks again for the video !
@forbiddenbox
@forbiddenbox 10 месяцев назад
Wow I really wish RU-vid had more advanced unity tutorials that kinda leave the unity api and go straight to C#
@bogoid
@bogoid 3 месяца назад
Ah thank you for posting this, I already have my own but I think this pattern needs more publicity among game devs, plain event handling gets out of control quick when building mid sized project's, let alone full featured, professional games.
@git-amend
@git-amend 3 месяца назад
I agree! Thanks for the comment!
@LlamAcademy
@LlamAcademy 4 месяца назад
I implemented this and generally found it pretty straightforward, but had a couple of issues. Because we're using a HashSet, if you have an event like "UnitDeathEvent" that is raised where a unit is also subscribed to "UnitDeathEvent"s we can end up having the HashSet getting modified while executing which is not allowed. I ended up replacing the core with something that required much less code - simply having a Bus where T : IEvent with: public delegate void Event(T args); public static event OnEvent; public static void Raise(T evt) => OnEvent?.Invoke(evt); every consumer then just does Bus.OnEvent += handler; (and -= handler to unsubscribe). After adding a dozen or so events with event bindings I found the implementation here (requiring constructing event bindings then assigning them) to be more cumbersome than the above. This is maybe more of an edge case, but thought I'd bring it up to you. Appreciate you sharing the topic with a Unity-focused implementation :)
@git-amend
@git-amend 4 месяца назад
Thanks for the comment. I haven't run into that issue myself, but definitely something to consider. Cheers!
@shadowking19871
@shadowking19871 16 дней назад
i run in to a similar error: InvalidOperationException: Collection was modified; enumeration operation may not execute. System.Collections.Generic.HashSet`1+Enumerator[T].MoveNext () (at :0) EventBus`1[T].Raise (T event) (at EventBus.cs:11)
@mracipayam
@mracipayam 7 месяцев назад
Wow your videos are really intermediate, i am watching at least 3 times for getting all understandings.
@V-post
@V-post 6 месяцев назад
There needs to be an ngrx equivalent for unity. You’ve essentially created a high level version of it/ redux. Good video.
@AnEmortalKid
@AnEmortalKid 24 дня назад
Holy hell that type definition part was pretty magical my dumb impl would have had a map of t to event bus and a utility to initialize those. So by creating the different event buses of specific types and hold8mg a static reference to them, that basically acts the same as having something like PlayerEventBus extends EventBus and the runtime can handle it ? Wow.
@git-amend
@git-amend 24 дня назад
Thanks! Glad you liked the vid, hope it gives you some ideas for your own project!
@TheArghnono
@TheArghnono 10 месяцев назад
This is incredibly useful. I especially like the addition of some clever reflection.
@git-amend
@git-amend 10 месяцев назад
Great to hear!
@PZMaTTy
@PZMaTTy 5 месяцев назад
This is well done code, i'm subscribing to the channel because i like "good" code not "easy" code. All good with dragging gameObjects to public variables in the inspector. But sometimes projects are extremely much more complex and this is an elegant, scalable and quite robust solution for its function.
@git-amend
@git-amend 5 месяцев назад
Thank you! Welcome aboard!
@Benoit.Prigent
@Benoit.Prigent 10 месяцев назад
Hello sir, very nice video as usual ! Keep up the good work. It is always a pleasure to see advance c# and game programming pattern in action. I personnaly like this content way more than other too specific and very shallow Unity tutorials. Beside that, I wanted to know what is your take on hiding versus keeping clear dependencies. For example, when using this type of event busses, it will "break" the callstack and make it fairly harder to debug. I feel like it is a good call for global game and system events, but for things like player events : we might want to know what is calling what and what are the underlying link between all the systems and scripts in our scenes... Thanks for reading me ! :p
@git-amend
@git-amend 10 месяцев назад
Hey, thanks for the appreciation and the insightful point! You've touched on a key topic of managing dependencies, and how it can affect debugging. I totally get the concern, especially as your project grows. This sounds like a great topic for a future video where we could dive into the pros and cons, and explore solutions. Your feedback is super valuable, and it's ideas like this that help drive the content forward. Stay tuned, and thanks again!
@tobario
@tobario 6 месяцев назад
Cool method. I do almost the same but use Scriptable Objects to relay events. It's a nice way to decouple and visualize.
@rutchjohnson
@rutchjohnson 10 месяцев назад
Love this advanced class on Unity/C#. I'm not at this level but I love being exposed to it. I just don't understand why we would use what you just created over Unity Events.
@git-amend
@git-amend 10 месяцев назад
A few people have asked that question, so I added a paragraph outlining some of the advantages in the video description. We'll get into some of it in future videos.
@rutchjohnson
@rutchjohnson 10 месяцев назад
@@git-amend oh awesome! Than you :) Sub’d
@TheAndyW19
@TheAndyW19 10 месяцев назад
I've been considering how to properly structure the architecture of my code in recent months as my code always ended up in a mess of references and Singletons. This is the exact content I was looking for. Spent ages looking for different code decoupling methods and this seems like the best approach. Could you give any insight into the advantages of this system over the Event Channel system from your other video? From what I understand the main advantage from your other system is that it makes use of Unity serialization for the inspector via scriptable objects. Is there a scenario where you think that it would make sense to use both an Event Bus and Event Channel system? I look forward to your future content.
@git-amend
@git-amend 10 месяцев назад
Great! Thanks for your comment, I'm glad the video helped you out. Regarding your question, yes the main advantage of using Channels is serialization and the ability to create channels in the Editor - it would give a lot of flexibility to your team (or yourself) to add more channels without defining more Events in C#. Furthermore, it requires the objects using the Channels to hold a reference to the channel, which is a little more tightly coupled. I would also say that in the long run, it will be less flexible/powerful and may be harder to add some additional features as well. I would say there is room to use both an Event Bus and Event Channels, as long as you maintain a clear separation of concerns.
@TheKr0ckeR
@TheKr0ckeR 3 месяца назад
Since my plan is to get one of the best known developers in the industry, I am really appreciated you are showing the path to follow in an advanced way. Did you have some kind of roadmap to follow while improving yourself or you just randomly learn stuff? I feel like i am getting into advanced in c#, like creating editor tools, using advanced attributes and trying to create best modular scaleable way. But sometimes looking for topics to learn and getting overhead. And have you had a chance to try those attributes in Mobile or in a build? I sometimes feel unsafe using those since its like editor only. I feel like some stuffs would be broken.
@git-amend
@git-amend 3 месяца назад
If you look on the Discord server there is a pinned comment with recommended reading, it's a good progression path if you are looking for some great books.
@anasmostefaoui3027
@anasmostefaoui3027 9 месяцев назад
The book reference in this video is amazing! very helpful, I'm waiting for my copy to ship :D . It would be very helpful if you can drop reference like that in the future videos. Thanks again for the amazing content.
@git-amend
@git-amend 9 месяцев назад
Haha! Great! It's a thick book, lots to digest in there. I'll mention a few more in the future!
@antijulius
@antijulius 29 дней назад
Just implemented this in a project of mine - thank you! You were soliciting suggestions for improvements and teasing a future video that builds on this but honestly - and maybe I'm dumb - I can't think of how to expand on this system. It kind of just... does what it's supposed to. Maybe I haven't used it enough to run into some of its limitations? What are some ways you would expand on this - and are you still planning a follow-up video? I'm also curious how you generally handle cross scene communication for a medium sized project. Right now I'm using you service locator and this event bus and SO event channels. Not sure whether to ditch the event channels and lean more into the event bus... Still kind of finding my groove with this whole thing. Curious if you have a preferred workflow? Not looking for an absolute truth or anything - just curious about your preference. Thanks again - seriously - for all the great content!
@git-amend
@git-amend 29 дней назад
The most impactful addition to the Event Bus would be one-shot events (fire once then remove themselves from the system). Regarding workflow, I tend to only use Event Channel SOs if there is a real need to configure them inside the Unity Editor. If I can do everything in code, I will, because I can haha. But sometimes you'll work with others and they will need that flexibility. Thanks for the comment!
@antijulius
@antijulius 29 дней назад
@@git-amend Oh, one-shots would definitely be nice. Thanks for the response!
@halivudestevez2
@halivudestevez2 10 месяцев назад
Thanks for this advanced topic. I always wish for some (UML) diagrams for easier understanding.
@danlleo
@danlleo 8 месяцев назад
Your content is pure fire, keep it up. Thank you, you're a great tutor!
@git-amend
@git-amend 8 месяцев назад
Thank you very much, will do!
@termite1737
@termite1737 10 месяцев назад
Your channel is gold :))), I can learn advanced topic from you as a fresher, keep going !!!
@git-amend
@git-amend 10 месяцев назад
Happy to hear that!
@joewilliams8286
@joewilliams8286 10 месяцев назад
Great video mate, will definitely look to implement such a system in my next project
@git-amend
@git-amend 10 месяцев назад
Right on! Glad you liked it!
@Taffaz
@Taffaz 9 месяцев назад
Great video and really informative. Previously I've used C# events and EventHandlers and im struggling to understand the benefits this provides over that method. Seems to add a fair bit of complexity with the reflection but woild appreciate a quick one liner for why this is better.
@git-amend
@git-amend 9 месяцев назад
Thank you! The main benefit of this model is complete decoupling. In the conventional C# event model, classes subscribing to events must be aware of the class that triggers these events to subscribe effectively. However, in the EventBus model, the entities involved in emitting and receiving events are not required to be aware of each other at all. They only need to know the specific event types they are interested in. The reflection is so that we can bootstrap, maintain a list of all EventBuses, and perform global operations such as clearing them - which is not guaranteed when Domain Reload is disabled. see docs.unity3d.com/Manual/DomainReloading.html
@Taffaz
@Taffaz 9 месяцев назад
@@git-amend That makes perfect sense, thanks for that. Just found your channel and working my way through your videos. They definitely fill a void of content for intermediate level unity devs so thanks again.
@kadircalloglu2848
@kadircalloglu2848 6 месяцев назад
Zenject's Signal Bus system is similar to the Event System, but I noticed a potential issue: instantiating a "new" in OnEnable might lead to unnecessary overhead and overload. For example, in your Health bar script
@martin.m.kloeckener
@martin.m.kloeckener 6 месяцев назад
In your Event Channel video you talk about the ambulance pattern for the Event Bus. Can you elaborate on this? How is it being used to prioritize events?
@git-amend
@git-amend 6 месяцев назад
The details of how to go about implementing this are more complex than I can describe in a comment, but the main idea is that the Ambulance Pattern suggests segregating emergency events from normal events either into separate queues or otherwise marking them as higher priority. The goal is to ensure that high-priority events are handled promptly without completely sidelining regular traffic. You can read a bit more about it here: dev.to/lazypro/design-patterns-of-event-driven-architecture-3a79
@martin.m.kloeckener
@martin.m.kloeckener 6 месяцев назад
@@git-amend Thank you for the answer!!
@jzeltman
@jzeltman 5 месяцев назад
Thank you for the video. Learned a bunch
@git-amend
@git-amend 5 месяцев назад
Glad it was helpful!
@artemaslanyan7503
@artemaslanyan7503 Месяц назад
Thanks alot brother. Would help if you tell us when to use event, event chanels and even buses. I am just starting out, and I "borrowed" your implemenetation of event bus and it works perfect. But would like to know when to use other means of communication between scripts.
@git-amend
@git-amend Месяц назад
Sure, maybe we can touch on that in an upcoming vid.
@ahmedmohammedfahmy5093
@ahmedmohammedfahmy5093 7 дней назад
Thanks bro for this great toutorial
@git-amend
@git-amend 7 дней назад
Yes, that is exactly right.
@eduardomiraldo4437
@eduardomiraldo4437 2 месяца назад
Hey, thanks for the tutorial! One thing I am not sure I fully understood was the purpose of adding the PredefinedAssemblyUtils class and all that part. So, we are doing all that to make sure we have got all the types that actually implement the IEvent interface even if they are static? Also, to put it simple, the eventBus is responsible for having a list of Actions that are invoked every time the event is raised. Lastly, how impactful in performance is passing managed types as arguments? Is there any point where I should consider just passing a health value instead of passing the whole Player object?
@git-amend
@git-amend 2 месяца назад
The purpose of bootstrapping the system is to avoid allocations at runtime. By going through the assemblies we can preemptively create all the static types of EventBus that we will be using in the game. This avoids the potential performance hit during gameplay. Your understanding of the purpose of the EventBus is correct, it manages all the registered actions that should be performed when an event is raised. For your final question, there is little difference in terms of performance when passing a reference instead of a value. However, a reference has a lifecycle, and you have to ensure that there is something there in memory when you try to access it (in case the Player was destroyed for example) so you have to ensure null checks, and error handling.
@alexsolovyov3322
@alexsolovyov3322 10 месяцев назад
Great video, thoroughly explaining a custom event bus. Though, I'm not sure what are the benefits using it over the built-in Action?
@git-amend
@git-amend 10 месяцев назад
Hey there! I’m glad you enjoyed the video. You bring up a great point. Using a custom event bus and C#'s built-in Action both have their places. The custom event bus shines in larger or more complex projects where decoupling is essential. It helps in organizing code in a way that various parts of your system can communicate without needing to reference each other directly. This way, you can change one part of your system without having a domino effect of changes across the codebase. It can help in categorizing events, logging, and even debugging to some extent by providing a clearer overview of what's happening in your game. We'll be adding some features such as those in a future video. On the other hand, C#'s built-in Action is straightforward and might be easier to manage in smaller or less complex projects.
@alexsolovyov3322
@alexsolovyov3322 10 месяцев назад
@@git-amend Makes sense, thanks
@kuraikage15
@kuraikage15 2 месяца назад
Hey, awesome tutorial. Just 1 question and this could be a very noob question. You are calling ClearAllBuses from Unity Editor only block which takes care of clearing in the editor itself but I'm assuming it isn't required on a build since they should be cleaned up automatically right?
@git-amend
@git-amend 2 месяца назад
Yes, that’s correct.
@kuraikage15
@kuraikage15 2 месяца назад
@@git-amend thanks!
@Cloud-Yo
@Cloud-Yo 6 месяцев назад
Finally got this working after consulting your code on the Git, I noticed that the change you made to the GetTypes Method did the trick. Correct me if Im wrong but the bootstrapping is unnecessary and can be done manually for each event type we create? (Tho your solution is far more elegant, dynamic and useful)
@git-amend
@git-amend 6 месяцев назад
Great, glad you have it working. The main reason for the bootstrapping is so that you have a complete list of all the Event Types without having do manually add them. But it has another purpose, which is that Unity does not guarantee the clearing of statics when coming in and out of play mode, particularly when Domain Reload is disabled, so clearing the Event Buses is easily handled automatically if the system knows ahead of time what all the types are. See the bit about statics here: docs.unity3d.com/Manual/DomainReloading.html
@Cloud-Yo
@Cloud-Yo 6 месяцев назад
@@git-amend I understand, thanks for clarifying. I can see this being useful in a lot of cases too.
@kelecik
@kelecik 7 месяцев назад
~QUESTION~ First of all thank you for the video, you mentioned the difference from the classic static manager in the comments, this was great, the advantages are really more than the other, but I have this question in my mind, I just need an event to listen to whether the game is over or not. will I have to open an empty struct just to do this listening movement or is there a point I missed?
@git-amend
@git-amend 7 месяцев назад
You could either have an empty struct with no values inside because it serves only on purpose, or you might want to have the event contain a value so that you can use it for more than just game over - maybe game paused, restart level, etc.
@kelecik
@kelecik 7 месяцев назад
thanks for answering. excellent channel. keep up the good work.@@git-amend
@OdysseyHome-Gaming
@OdysseyHome-Gaming 4 месяца назад
Thanks for this series. I'm nearing the completion of a Bachelor of Games (Programming Major) and still yet to learn how to make games in Unity3D in an extensible way. These videos along with Iain McManus "@IainTheIndie" are helping me out immensely (his is an underrated chanel). One thing that I'd love to be able to do with events is have a debugging tool / window that lets me see what events have been registered and allows me to trigger any event during runtime from the window with overriden arguments if provided. This bus looks like a good foundation for exposing that infomation to an editor window (would be a cool tutorial).
@git-amend
@git-amend 4 месяца назад
Nice. I've watch some of Iain's videos, they are very good. The idea for extending the bus with a tool is a good one. I have some other additions to this code as well, so maybe at some point this year we can extend it in a video.
@OdysseyHome-Gaming
@OdysseyHome-Gaming 4 месяца назад
Sweet. Also been meaning to ask about how best to design event structs for this bus system. Like Event CloseUIScreen {} Event OpenUIScreen {Type screen} Event OpenUrl {String address} Or Event UIEvent { bool IsClosing, Type screentoShow string address } My gut says the first is better since it avoid excessive multicasts, but the later one feels cleaner because i encapsulate ui data into an explicit event type.
@git-amend
@git-amend 4 месяца назад
@@OdysseyHome-Gaming I think it really depends on your game. Be careful of temporal coupling, so if you have multiple fields in the struct they should all be very closely related and the outcomes they cause should all need to happen at the same time. This is often a breeding ground for hard to spot bugs, and it makes it harder to refactor if you need to later on. I like having multiple fields, but the more complex the struct becomes, the more challenging it can be to work with as well.
@noobcola
@noobcola 7 месяцев назад
Quick question: why is it important to bootstrap the Event Buses? The event bus system seems to work fine without the bootstraping code. By the way, thanks for making this video!
@git-amend
@git-amend 7 месяцев назад
Thanks! Instantiating static classes has some overhead, so if you have a lot of different Events it can be beneficial to create all your Event Busses ahead of time. Additionally, it allows you to efficiently create a list of all of them so that you can clear statics when coming out of Play Mode, something that is not guaranteed by Unity and can cause memory leaks. (Or clear them anytime you want, or perform other diagnostics where you might want a list of all existing Event Bus instances)
@mikhailhumphries
@mikhailhumphries 10 месяцев назад
Maybe in a couple of years I'll understand this.
@git-amend
@git-amend 10 месяцев назад
Little bit at a time! 👍
@opxv
@opxv 10 месяцев назад
Thanks for your videos! This is by far the cleanest implementation of an event bus I found on YT so far, ready to use. And the fact, that it's not data driven with scriptable objects, makes it even better imo. Now I am more on the beginner side of things and I've tried to use such a system in my game, but I always ran into troubles. And maybe I don't understand it fully, so I figured I might just ask. In my head, the event bus makes a lot of sense for just one player. But what if I had a player, buildings and chests with inventories and those inventories have slots and the slots have a stack component. For the stack component I guess I'd make a SlotEvent or even a StackEvent, so I can update the stack size on display. So if some system updates a stack and the event gets fired on the bus, all stack displays currently showing, receive the event, right? How would the right stack display know it has to change to the new number? I'd appreciate an answer for this or just tell me, I'm getting it all wrong :D Thanks.
@git-amend
@git-amend 10 месяцев назад
I personally wouldn't use an Event Bus to manage an inventory system, because as you rightly point out - there would be a lot of events. Typically you need to expect some coupling between an inventory container and it's UI display. Maybe today's video about Memento which features the beginnings of building an inventory/ability UI system will shed some light on that. I think, because so many people have requested it, there will be a full inventory tutorial in the future, including what you've just described.
@nicolasgerard2476
@nicolasgerard2476 2 месяца назад
I added a tiny bit of syntactic sugar on the event bus, I thought some might like it public static class EventBus { public static void Register(EventBinding binding) where T : IEvent => EventBus.Register(binding); public static void Deregister(EventBinding binding) where T : IEvent => EventBus.Deregister(binding); } With this, you don't need to qualify the type of binding you want to register to the event bus as it can be deduced. So when registering the binding: EventBinding myEventBinding; Instead of writing: EventBus.Register(myEventBinding); You can write: EventBus.Register(myEventBinding);
@git-amend
@git-amend 2 месяца назад
Looks like a good addition, thanks for sharing that!
@atherissquamigera7425
@atherissquamigera7425 6 месяцев назад
Hi, I don't understand the need for EventBusUtils. why do you need to cache a list of eventBusTypes and eventTypes? if it is for the Clearing method, couldn't you create a method inside the EventBus class to clear itself when the Unity initializes itself? the second thing that I don't understand is why did you use the explicit interface definition for the EventBinding class, what is the use case?
@artemstolyga6829
@artemstolyga6829 8 месяцев назад
First thanks again for making these videos! I was following you quite well through the first section. But I kind of lost in the second and third section. While I sort of understand what you are doing, I don’t really understand why. Could you please explain? 🙏
@BrontoKroxig
@BrontoKroxig 6 месяцев назад
Hi, awesome tutorial as always, I really love your content. I'm really trying to push my Tech Director to let us use EventBus pattern (Signal Bus in our case, cause we use Zenject), but he always says no, his reasoning is: 1. It scalates poorly -> It's really easy that we forgot all the events that we have 2. Is hard for Juniors to not messed up -> They can call events from everywhere 3. Is hard to debug -> Once events can call events, you cannot ctrl+click into the code to trace the error What will you say to my Tech Director about those points?
@git-amend
@git-amend 6 месяцев назад
I find it a bit surprising that you use Zenject but are opposed to an Event Bus. However, it's really his decision. Even though all the points you've mentioned could be mitigated using various strategies, sometimes people don't want to introduce more complexity than they feel can be handled by the team. The best approach for introducing a concept that a leader/manager doesn't want is to find a valid use case where you have a real problem to solve in the current project and the best (or only) way to solve it is with the solution you want them to try.
@ArnCiS96
@ArnCiS96 Месяц назад
Well you should combine with your service locator, to have have consistent API for both ServiceLocator and EventBus, that means that EventBus have assigned for global, scene and gameObject level. I used this approach to scale multiplayer matches where each match have own isolated scene and each player own isolated services and event buses. Lets try to scale up your Cart netcode to handle N matches at same time on server side, what about this challenge?
@git-amend
@git-amend Месяц назад
Sounds very interesting, but also very niche. The goal of my vids is not to make these kinds of complete solutions that appeal to a select few people, but instead to give you the knowledge or ideas you need to be able to do these kinds of things yourself as you require them.
@ArnCiS96
@ArnCiS96 Месяц назад
@@git-amend Yea I know, but video about: How to make scalable dedicated multiplayer server? Or something like MMO related stuff should be interesting for people.
@valerakornienko2501
@valerakornienko2501 10 месяцев назад
I enjoyed your video and gained a lot of new insights. However, I've encountered a minor problem. When attempting to retrieve types in the GetTypes method, I couldn't find the "Assembly-CSharp-firstpass" in the assemblies. As far as I understand, this assembly is typically generated when a "Plugins" folder is employed (though I'm not entirely certain about this), and I don't currently have any plugins in my project.
@git-amend
@git-amend 10 месяцев назад
I've been able to replicate the issue - in this case, the Dictionary won't have an entry for that assembly. In the PredefinedAssemblyUtil use TryGetValue before calling the AddTypesFromAssembly method. assemblyTypes.TryGetValue(AssemblyType.AssemblyCSharp, out var assemblyCSharpTypes); AddTypesFromAssembly(assemblyCSharpTypes, interfaceType, types); assemblyTypes.TryGetValue(AssemblyType.AssemblyCSharpFirstPass, out var assemblyCSharpFirstPassTypes); AddTypesFromAssembly(assemblyCSharpFirstPassTypes, interfaceType, types); I'll add this safety check to the codebase - thanks for pointing that out!
@omeryilmaz1021
@omeryilmaz1021 3 месяца назад
is this system able to be used as an Observer pattern for systems to communication (maybe creating a dictionary would differentiate non-arg actions ) and there s no assembly named Assembly-CSharp-firstpass only Assembly-CSharp exist
@git-amend
@git-amend 3 месяца назад
See: docs.unity3d.com/Manual/ScriptCompileOrderFolders.html
@namtranhai8456
@namtranhai8456 10 дней назад
i got the error "InvalidOperationException: Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true." it happen when i add some event like this "public struct AddResouse : IEvent where T : IResource" .
@namtranhai8456
@namtranhai8456 10 дней назад
if (!clearMethod.ContainsGenericParameters) clearMethod?.Invoke(null, null)C Currently I work around with this code but this is not the solution ofcourse.
@git-amend
@git-amend 10 дней назад
This likely happens because you are trying to use a generic type AddResouse in a context where the generic type T has not been fully specified. But it could also be because you have misspelled Resource as Resouse. The proper solution involves ensuring that the method is fully constructed (i.e., all generic parameters are specified) before attempting to invoke it.
@coryleach
@coryleach 7 месяцев назад
I've made very similar bus systems in the past but I never thought about adding a bootstrap for all the different bus types maybe because I usually have been working with AOT only platforms. What's the main motivation to generate all of the types on load? I suppose there could be a minor frame drop the first time a bus is used? I'm also wondering now if MakeGenericType plays nice on platforms that don't allow JIT
@git-amend
@git-amend 7 месяцев назад
The main motivation is to minimize the impact of creating a bus at runtime, as you noted. As far as I understand MakeGenericType has been fully supported for quite a while - but there are some caveats. See: docs.unity3d.com/Manual/ScriptingRestrictions.html
@KjipGamer
@KjipGamer 9 месяцев назад
Oh boy! I've been working with C# for the better part of 7 years and I was barely able to follow. Shows just how much I'm missing!
@git-amend
@git-amend 9 месяцев назад
I think that's the part I like about programming the most - you never stop learning new things!
@nhatlinhtran3575
@nhatlinhtran3575 7 месяцев назад
thank you for sharing
@git-amend
@git-amend 7 месяцев назад
My pleasure
@gamerpokigamer6261
@gamerpokigamer6261 10 месяцев назад
Hello! There is something that I don't understand, why are you generating the EventBus generic type for each IEvent types. Isn't C# generate this for you when you doing "EventBus.Register" like in C++ ?
@git-amend
@git-amend 10 месяцев назад
The code in your comment does work just as you described and would indeed create a static class of that type. The key difference between C++ and C# is the point in time when the actual type-specific code is generated. In C++ they are a compile-time construct. C#/.NET generics are bound at runtime. In C#, proactively creating your static types at startup is generally more performant in terms of consistent runtime behaviour, as it avoids the potential for delayed initialization during gameplay, which can cause frame rate drops or uneven memory usage. In addition, the pattern used here also allows us to efficiently perform global operations, such as clearing all buses, which is necessary when moving in and out of play mode if you aren't reloading the domain every time - otherwise, you'll have duplicates registered with your buses. Cheers!
@laserbean00001
@laserbean00001 7 месяцев назад
So does this design pattern eliminate the use of the Observer pattern? Also, I currently already have an event manager system and I'm not sure if this video is overkill or not...
@git-amend
@git-amend 7 месяцев назад
I would say that it does not eliminate the use of the Observer pattern - there are still many times when the Observer pattern is useful, especially the generic observer. This is just a tool that will allow for completely decoupled messaging in your project.
@laserbean00001
@laserbean00001 7 месяцев назад
@@git-amend I'm still a bit confused. but thank you. Your tutorials are amazing.
@robertdorn4081
@robertdorn4081 6 месяцев назад
Why not create a EventBus at runtime when it's first needed? As soon as one Script subscribe to an event or another script will raise the event, then the bus can be created when it's not done already
@git-amend
@git-amend 6 месяцев назад
Instantiating static classes in C# has some overhead, so if you have a lot of different Events it can be beneficial to create all your Event Busses ahead of time and avoid potential problems during gameplay. Additionally, it allows you to efficiently create a list of all Busses so that you can clear statics when coming out of Play Mode, something that is not guaranteed by Unity when Domain Reload is disabled, and can cause strange behaviour and memory leaks. You might also want to clear them anytime, or perform other debugging or diagnostics on all instances. See the bit about Unity statics here: docs.unity3d.com/Manual/DomainReloading.html
@rechnight
@rechnight 9 месяцев назад
Love your videos, they have been really helpful! I have a doubt, what are the benefits (or not) compared to an Interface based EventBus (IListener kinda one)?
@git-amend
@git-amend 9 месяцев назад
I'm glad you find the videos helpful! Your question is difficult to answer because there are many ways to implement an EventBus with interfaces, including the one in this video. For the sake of answering the question, I'll just assume that you are wondering about the pros and cons of this EventBus compared to a non-generic EventBus. The main difference is going to be in how you store the listeners, and this affects performance as well as ease of future extensibility. In a non-generic implementation, you might have only one EventBus that maintained a Dictionary of Types and Bindings instead of a HashSet - for example, if you had hundreds of event types - it would be less performant at runtime, but it would have a smaller memory footprint overall. It might also require more casting and type-checking at runtime, depending on other features you choose to add to it. In a Generic EventBus it might have a slightly higher initial cost but will be faster at runtime. There is no runtime initialization of statics and it can use a HashSet to store listeners. Additionally, it is going to be somewhat easier in the future to add new features such as direct registration (registering a callback without a binding) as well as it will simplify handling events that can be awaitable in coroutines and async operations. You could still do these things with another style of EventBus, but it would be slightly more cumbersome because you have to do a lookup on the Type every time an EventBus method is called. In the end, the choice is really up to you - a few small changes, and you could have one EventBus that manages all event types based on an interface. In a small project, you might not notice any difference, but in a larger project these things will add up and ultimately you might want to go one way or the other depending on how many event types you have. Keep in mind that having hundreds of types of events for a project suggests that the events are too granular and will eventually become unmanageable.
@rechnight
@rechnight 9 месяцев назад
@@git-amend Thanks for the detailed reply! Will analyze your reply careful and check the differences in my current implementation to the one you presented here. My current implementation is what you guessed, a Dictionary of Type and object (either IListener or Action), but to subscribe to an event is just one liner, and from what I can see from this implementation, need to create a new Binding and register it to the EventBus every time, right? But then you mentioned the possibility of adding features such as direct registration without a binding, how could we achieve that with the implementation presented in the video?
@git-amend
@git-amend 9 месяцев назад
@@rechnight Those additional features I mentioned are going to be included in a 'part 2' video! Stay tuned!
@guillem99
@guillem99 9 месяцев назад
Excellent video! Do you think it would increase the game's loading time if we had hundreds of event classes?
@git-amend
@git-amend 9 месяцев назад
If you need hundreds of different Event types, I would modify the code to use one (or just a few) different Event Buses that maintain a Dictionary of Event type / Event Bindings - it will be more efficient and manageable.
@guillem99
@guillem99 9 месяцев назад
@@git-amend I'm not really sure I understand what you mean. Could you show me a concrete example?
@ggwp8618
@ggwp8618 10 месяцев назад
Hi i seem very lost in this video. I have using unity for 1.5 years or so. But this stuff just went over my head
@git-amend
@git-amend 10 месяцев назад
This video is quite advanced, even for this channel. Don't worry if you feel overwhelmed by any new or complex concepts, especially in a field as expansive as Unity development. Everyone is on their own learning journey, and every step, no matter how small, contributes to your growth as a developer!
@ggwp8618
@ggwp8618 10 месяцев назад
@@git-amend thanks for the reply i want to you suggest a good learning point for a developer like me I pretty much know all the stuff about the delegates actions abstract class interfaces etc
@git-amend
@git-amend 10 месяцев назад
@@ggwp8618 ​ First of all, keep watching my channel! I tailor most of my content to developers on your level. Another good thing to start doing is dissecting tools from the Asset Store or an open-source project and trying to understand how it works. If you stumble upon complex sections, leveraging AI tools like ChatGPT or the JetBrains AI Assistant can help explain the code, and you can sketch diagrams to visualize the relationships between classes and methods. Do that for a couple hours every weekend, and you will learn a ton!
@ggwp8618
@ggwp8618 10 месяцев назад
@@git-amend thanks for your valuable suggestion i will keep that in mind.
@user-he4ly5yy8k
@user-he4ly5yy8k 7 месяцев назад
Thx for the videos !!! 😊
@git-amend
@git-amend 7 месяцев назад
No problem!!
@PuppetDev
@PuppetDev 10 месяцев назад
Didn't know you could use static generics to store separate data like that. Are we doing the whole bootstrapping part just to call MageGenericType? Seems a bit odd to me, but I guess the compiler doesn't handle static+generic properly otherwise or something?
@git-amend
@git-amend 10 месяцев назад
Thanks for your question! The bootstrapping process automates what would otherwise be a manual task of creating separate EventBus instances for each event type. By using Type.MakeGenericType, you dynamically generate these instances at runtime, saving manual effort, reducing potential errors, and making the system more maintainable and scalable. This way, as new event types are introduced, the system adapts without needing manual updates.
@bdd740
@bdd740 10 месяцев назад
Thanks a lot.
@git-amend
@git-amend 10 месяцев назад
Most welcome!
@DuckeryDoo
@DuckeryDoo 9 месяцев назад
Doing it this way, there is only one "global" event foreach eventType, right? So for example, if there is not only the player, but also other things like enemies with health/mana, this approach doesn't scale well, or am I missing something? If that is the case, how could one improve this? Thanks for the video, i really appreciate them! :)
@git-amend
@git-amend 9 месяцев назад
Thanks for your comment/question! This EventBus would have one static Bus created for every Event type, that is correct. If you are planning to have hundreds of different Event types you would have to start thinking about how to handle it differently. The most likely scenario is that you would use a non-generic EventBus that would store a Dictionary of all Events (or EventBindings) by Type, and perform lookups every time you need to interact with the Bus. Your startup would be faster, and you would have an overall lower memory footprint, but at the cost of performance. However a word of caution would be that if you have hundreds of Event Types this is a code smell that suggests there could be a better design where your Event Types are not so granular.
@KhanhLe-in7yi
@KhanhLe-in7yi 8 месяцев назад
I don't understand class EventBusUtil and PredefinedAssembly. Can you briefly explain it to me?
@git-amend
@git-amend 8 месяцев назад
It might help to look at the source repository - there are detailed comments explaining each class and it's methods: github.com/adammyhre/Unity-Event-Bus
@KhanhLe-in7yi
@KhanhLe-in7yi 8 месяцев назад
@@git-amend Thank you !!!
@NghiaTran-pg1is
@NghiaTran-pg1is 10 месяцев назад
Hi, this system looks great. I just wanna ask about how can i custom it to fit my project? In my game there is the same kind of button but each of them active/deactive or move different things but in your sample code there just one player object that deliver the event. I wonder is there any way i can change the listeners for each instance of button like scriptable object or something . Thank you so much.
@git-amend
@git-amend 10 месяцев назад
Each object in your game can create its own listeners (bindings) for any event. However, what you describe might be better done with an Event Channel - check out my video on that and see if that's a better method for your usecase.
@andrewallbright
@andrewallbright Месяц назад
How in the world did you learn/figure how to do the assemblies trick?
@git-amend
@git-amend Месяц назад
Combination of Unity documentation and looking through some open source projects... and maybe some trial and error lol
@andrewallbright
@andrewallbright Месяц назад
​ @git-amend Yea but there's a difference between newing up event bus instances needed in some static class somewhere (like most would do) and hooking into the assembly loader to run some code before unity lifecycle methods trigger so event buses are basically automatically created for any class/struct implementation of IEvent. Watching this video is like watching a chicken be a chicken and then all of a sudden it gets on a skateboard, does a kickflip, and then goes back to being a chicken. I have so many questions lol
@muhammadmuhajir3457
@muhammadmuhajir3457 9 месяцев назад
Very cool, how is this approach compared to scriptable object approach?
@git-amend
@git-amend 9 месяцев назад
Well, this approach is less coupled for sure which I prefer, but it has the disadvantage that a game designer cannot simply create a new type of Event from the Unity editor. To be honest, I would probably use both methods in a larger project because both of them have their own strengths and I like the abstraction of an SO as a 'channel' of information about a specific subsystem, like all Weather messages or Game state messages, that are a bit more general in nature.
@banditbloodwyndevs8782
@banditbloodwyndevs8782 9 месяцев назад
Your implementation of the EventBus is awesome. But I don't see the point of the assembly utilities and the bootstrapping. Even without these the EventBus works and sends all events I want to the listeners I registered. You fill these ReadonlyLists in the EventBusUtil class with all existing relevant types, but I don't see any usings. What is happening there? Could you explain this a bit more?
@git-amend
@git-amend 9 месяцев назад
Thanks for your question! Maintaining a read only list of the buses allows us to efficiently perform global operations, such as in this video, we are clearing all buses, which is necessary when moving in and out of play mode if you aren't reloading the domain every time. Otherwise, you'll have duplicate bindings registered with your buses since they are static classes. You might want to add some debugging or diagnostics in the future (or other features), and this also makes it easy. Cheers!
@banditbloodwyndevs8782
@banditbloodwyndevs8782 9 месяцев назад
@@git-amend But why should I have duplicate bindings registered, just because of switching from Editmode to Playmode repeatedly? I register and deregister them in the OnEnable and OnDisable methods. Or is that a Unity specific thing I don't understand right now?
@git-amend
@git-amend 9 месяцев назад
@@banditbloodwyndevs8782 When Domain Reloading is disabled in Unity, static fields and event handlers are not automatically reset upon exiting Play Mode. This can lead to event bindings being registered multiple times, causing performance issues and unexpected behaviours. Clearing all Event Buses when exiting Play Mode ensures these are properly reset, maintaining a clean and predictable scripting state across different Play Mode sessions. It also mitigates human error. The best practice is to clean up after yourself so you don't get any surprises. docs.unity3d.com/Manual/DomainReloading.html
@uhhmir
@uhhmir 10 месяцев назад
amazing video! i dont understand the reflection part. it seems you just put all of the bus types into a list and never used it, is there some implicit initialization there?
@git-amend
@git-amend 10 месяцев назад
Thanks! The list of bus types is kept so that we can clear them all when exiting play mode (or anytime we want to clear all buses). The list could also be useful in the future; you might want to add more functionality, such as iterating over the list to attach diagnostic listeners or collect metadata on each of them.
@uhhmir
@uhhmir 10 месяцев назад
@@git-amend ohhhh thats very clever, thank you! just out of curiosity, would the domain reload not take care of that?
@git-amend
@git-amend 10 месяцев назад
@@uhhmir You are correct, a domain reload would clear that up. But there are scenarios where developers disable domain reload (which I do) to speed up iteration times when entering Play Mode. If domain reload is disabled, static event buses would retain their subscribers across Play Mode sessions, which could lead to unwanted behaviors or memory leaks.
@uhhmir
@uhhmir 10 месяцев назад
@@git-amend thanks for the quick response (: its amazing you go into so much depth in such a short tutorial
@alif-fgd
@alif-fgd 10 месяцев назад
Great video as usual! Can anyone point out the advantages of using an event bus built like that over something simpler like just an static event manager? I'm just curious and interested in discovering new ways to improve my games. Just an example to illustrate what I typically use: using System; using UnityEngine; public static class EventManager { public static event Action ResourceCollected; public static void OnResourceCollected(PlayerResources data) => ResourceCollected?.Invoke(data); } public class PlayerResources { public float Health; public float Mana; } public class Player : MonoBehaviour { private PlayerResources resources; private void OnEnable() { EventManager.ResourceCollected += EventManager_ResourceCollected; } private void EventManager_ResourceCollected(PlayerResources data) { resources = data; } } public class CollectableResource : MonoBehaviour { private PlayerResources resources; private void OnTriggerEnter(Collider other) { EventManager.OnResourceCollected(resources); } }
@git-amend
@git-amend 10 месяцев назад
Thanks for your comment! This is a very good EventManager and certainly capable of doing a lot. An EventBus system and a static EventManager both serve the purpose of enabling loose coupling between classes and components, but they do have some differences that might make one more appropriate than the other in certain contexts: The biggest advantage of the Event Bus over the EventManager class is the use of generics. By using generics and interfaces, the EventBus can handle any event type without having to explicitly define events and delegate types for each one. With the EventManager approach, you would have to define a new static event in the EventManager for each type of event which could potentially make your EventManager class very large in complex projects. Also, while both systems promote decoupling, an EventBus system pushes it a step further. In the EventBus model, the emitting and receiving parties don't need to know about each other at all. They only need to know about the EventBus and the types of events that they are interested in. In the static EventManager model, while the emitting party does not need to know about the receiving parties, the receivers need to know about the specific static event(s) in the EventManager, making it slightly more coupled. The decision between the two would typically comes down to the specific needs of your project. The static EventManager is quite straightforward to understand and use, and might be more than adequate for smaller projects or those where the types of events are quite limited. On the other hand, if you're dealing with a large project with many different types of events, or if you especially value the flexibility and decoupling offered by the EventBus system, then that might be the way to go.
@alif-fgd
@alif-fgd 10 месяцев назад
@@git-amend Got it! Thank you for taking the time to explain
@guillem99
@guillem99 9 месяцев назад
I think there might be a problem when calling Deregister on an EventBus from within the same EventBus Raise method, since we might remove an element while iterating.
@git-amend
@git-amend 9 месяцев назад
If this is a concern, maybe consider storing the bindings in a Queue instead of a HashSet. But I would say write some tests first because that would be less efficient. I think it really depends on your usecase.
@guillem99
@guillem99 9 месяцев назад
@@git-amend I fixed it by storing the items that we want to remove in a separate HashSet if we know that we are removing them while raising events. What do you think of this approach? static bool isInvoking = false; static readonly HashSet toRemoveBindings = new HashSet(); public static void Deregister(EventBinding binding) { if (isInvoking) { toRemoveBindings.Add(binding); } else { bindings.Remove(binding); } } public static void Raise(T @event) { isInvoking = true; foreach (var binding in bindings) { binding.OnEvent.Invoke(@event); binding.OnEventNoArgs.Invoke(); } isInvoking = false; foreach (var binding in toRemoveBindings) { bindings.Remove(binding); } toRemoveBindings.Clear(); }
@rechnight
@rechnight 9 месяцев назад
Create a copy of the eventbindings before invoking the methods. For that issue, I usually prefer a list, that I can iterate in revese
@guillem99
@guillem99 9 месяцев назад
@@rechnightI don't think that creating a copy every time I want to invoke an event is very efficient.
@rechnight
@rechnight 9 месяцев назад
@@guillem99 Yeah, I know... That's why I mentioned that I prefer using a List instead of a Hashset, so when I raise the event, I iterate in reverse order. The benefit of the Hashset is not having to check if the binding already exists (and maybe a little performance boost?), but does have its downsides as well
@mohokhachai
@mohokhachai 7 месяцев назад
More tutorials in future
@metaling278
@metaling278 10 месяцев назад
Amazing video. Do you mind adding a license file to the git repo? :)
@git-amend
@git-amend 10 месяцев назад
Thanks. I've added a license file.
@endihidir2087
@endihidir2087 8 месяцев назад
Thanks for your great system. I tried to add a feature to this system but I'm not sure if it's useful or not. I converted HashSet
@git-amend
@git-amend 8 месяцев назад
Sounds interesting - what's your use case for dividing event bindings into channels?
@endihidir2087
@endihidir2087 8 месяцев назад
In my default game system I Invoke my game states, like (previousState, nextState) but I Invoke this 3 times because my state changes can last for seconds. For example, If I change my state in 1 second I Invoke 3 events which are (previousState, nextState) using with different Actions. And I Invoke them on the start, middle and end of the process. Normally, I use 3 Actions for this situation and I generate new listeners for all of different events but if I use channels I can use just one event and I can divide it to 3 channels.
@git-amend
@git-amend 8 месяцев назад
@@endihidir2087 What if you included a variable to indicate the state change inside the EventType and sent it as data? Would that be possible for your scenario?
@endihidir2087
@endihidir2087 8 месяцев назад
@@git-amend Hmm yes it is possible but it means more if check. So I prefer this version :D
@endihidir2087
@endihidir2087 8 месяцев назад
@@git-amend I also added Priority feature for Listeners execution order for same event type.
@pliniojrm
@pliniojrm 7 дней назад
Wondeful solution. When you dive into the assembly types, it complicates my life as whenever any issue occurs, i'd have to dump my project because i wouldn't know how to solve it. IMHO it is a nice to see a event busput into the core of the engine to be used in the game, however if the Unity team changes anything related to it in their core, i bet the majority of people who choose this will have their project "broken", because they wouldn't know how to solve it. They would depend/rely on you or Unity team to come up with a solution IMPOV.
@pliniojrm
@pliniojrm 7 дней назад
IMO this solution is for advance users, if not proficient users. It makes a user, dependable from your knowledge or from Unity team.
@ragerungames
@ragerungames 10 месяцев назад
any plans for producing a course in future?
@git-amend
@git-amend 10 месяцев назад
I have thought about it - a full course would overcome a lot of the limitations of RU-vid. I'll keep you posted! Suggestions welcome!
@thetinkerer5322
@thetinkerer5322 21 день назад
This is great but maybe it was a miss opportunity at the demonstration of the Orb filling up portion. You call it in PlayerEvents but did not modify or use PlayerEvents. Instead it was just used to increase the orb's level which can be done locally without bindings... Can bindings support multiple characters and mobs? What if there are multiple players? Do you basically loop through all playerevents and find the one belonging to the specific player and than modify the variables in the struct?
@Goomero
@Goomero 10 месяцев назад
hey, as unity devs we are used to using a component based system while caching them as best practical practice, whats the point of an event interface system when you can already hold all ur events inside each component which you are already caching?
@git-amend
@git-amend 10 месяцев назад
The primary advantage is decoupling. With an Event Bus your components don't have to know anything about each other to communicate. Tightly coupled components can result in a cascade of changes when one part of your system is changed or removed. It also allows you to communicate across scenes, prioritize events, add logging and debugging and other features.
@Goomero
@Goomero 10 месяцев назад
@@git-amend this just feels like extra code just to hold all the events inside a single class, while basically tying ur whole system to that single central interface, what if I removed that system, it would break everything
@friedcrumpets
@friedcrumpets 10 месяцев назад
​@@Goomero most larger games run off central systems such as this. Following agreed upon patterns in larger teams can speed up team development and improve code readability overall, while aiding in decoupling classes as much as possible. Yes if you removed the system the game would break, but why would you do that? I would rather tightly couple to a central system than have one object whisper events down 5 objects to get to where it needs to be.
@Goomero
@Goomero 10 месяцев назад
@@friedcrumpets make it make sense
@friedcrumpets
@friedcrumpets 10 месяцев назад
​@@Goomero Okay. Humans have a central nervous system. It allows us to send signals back and forth from our brain to other parts of our body allowing us to function. Remove that and we're just flesh bags that can't move. Evolution deemed It's a lot faster for our body to communicate in this way. If we create a central nervous system for our game built from design patterns we can optimise for efficiency. The idea of decoupling is to make it simpler for our systems to function while reducing the need for systems to need any more than one or two supporting systems. In larger games it often happens that a system needs a system, needs a system, needs a system, needs a system etc. It doesn't take long before the spaghetti code gets wild. Patterns like this help prevent that spaghetti.
@zyps6462
@zyps6462 7 месяцев назад
This seems extremely overcomplicated and over-engineered without a practical use case. 😢 However, I will be making a simpler version for my Godot projects. So thanks for the inspiration. 😁
@luaykashef
@luaykashef 10 месяцев назад
Is it okay if I have been using Unity for 4 years and have released 3 games and don't understand anything from this?
@git-amend
@git-amend 10 месяцев назад
Of course! Even though I've been programming for decades, I still learn something new every day.
@luaykashef
@luaykashef 10 месяцев назад
@@git-amend pheww thank you for that 🙏
@Injabsful
@Injabsful 10 месяцев назад
but like whats the real use of this tho ?:D
@SaudBako
@SaudBako Месяц назад
Great for our programmers. Not so much for our designers.
@smackmybiatch
@smackmybiatch 10 месяцев назад
Needs to be simpler, not tied to unity
Далее
Memento: Capture Game State Snapshots in Unity
14:24
Просмотров 4,5 тыс.
How to get Spongebob El Primo FOR FREE!
01:36
Просмотров 13 млн
Средневековый киборг
00:39
Просмотров 534 тыс.
The #1 Way To Get Better At Programming
22:43
Просмотров 10 тыс.
Events & Delegates in Unity
13:20
Просмотров 55 тыс.
The Power of Scriptable Objects as Middle-Men
17:41
Просмотров 124 тыс.
Clean Code using the Strategy Pattern
12:34
Просмотров 13 тыс.
SIMPLE Tip For Better Unity Game Architecture
12:57
Просмотров 31 тыс.