avatarMina Pêcheux

Summary

The context discusses refactoring the event system in a Real-Time Strategy (RTS) game project using Unity and C#.

Abstract

The context presents an interlude in an ongoing RTS game project tutorial series, focusing on improving the event system. Initially, the project implemented a simple event mechanism using an intermediate struct, CustomEventData, to represent the type of data that could be sent in an event. However, this implementation is far from ideal, as it requires remembering to add fields to the CustomEventData struct and updating all constructors as more data types are added. To address this issue, the author proposes a new EventManager class that leverages the C# object variable type and function overloading to automatically register events as typed events if some data is provided. The updated class removes all usage of the CustomEventData type and merges the trigger/listeners functions using overloads. The context also includes code snippets illustrating the changes required in various scripts, such as UIManager, BuildingButton, and UnitManager.

Opinions

  • The author believes that the initial implementation of the event system was not ideal, as it required constant updates to the CustomEventData struct and was user-unfriendly in the long run.
  • The author suggests using the C# object variable type and function overloading to improve the event system, making it more efficient and easier to manage.
  • The author provides code snippets and instructions for updating various scripts to match the new system, demonstrating their proficiency in Unity and C#.
  • The author emphasizes the importance of removing the CustomEventData class to avoid future complications and improve the overall event system.
  • The author concludes that this interlude was a quick and manageable fix to a small issue, highlighting their proactive approach to problem-solving.
  • The author encourages readers to follow their tutorial series and provides links to additional resources, such as their ebook and Github repository.
  • The author promotes their website as a source of more blog posts about tech, AI, and programming, showcasing their expertise in these areas.

RTS Interlude #2: Refactoring the event system (Unity/C#)

On with our RTS project — in this interlude, we’re going to improve our event system!

⬅️ Tutorial #10: Moving the camera| TOC | Tutorial #11: Adding a day-and-night cycle ➡️

📕 Get the ebook and bonus material on Gumroad! 🚀 Find the code of this tutorial series on my Github!

Several weeks ago, we implemented a simple event mechanism that allows us to better separate the systems in our game and avoid too-strict relationships. The first draft was meant to be very explicit and, because our class hierarchy was not as clearly defined as it is now, it was easier to use an intermediate struct, CustomEventData, to represent the type of data that could be sent in an event.

However, this implementation is far from ideal. In particular, if we start adding more and more data types to our events, we’ll have to remember to add fields to this CustomEventData struct and update all constructors. And differentiating between "typed" and "not-typed" events was important at first to understand the event system well, but it's a bit user-unfriendly in the long run.

Now that we’re more fluent with C# and type casting (especially thanks to our multiple glances at polymorphism and inheritance), we can improve this system and leverage C# object variable type! :)

Refactor of the EventManager class

The new class I propose for EventManager has two main differences with the previous one:

  • typed events don’t use a CustomEventData class anymore, rather we'll be using the C# object variable type that is very "lazy" and can be casted into anything quite easily further down the road (it's sort of like a "any type of variable is accepted here" flag ;))
  • we don’t differentiate between events and typed events anymore in our trigger/listener calls: instead, we’ll take advantage of C# function overload to automatically register the event as a typed event if some data is provided, else as a plain old (non-typed) event

So here’s the full code of the new EventManager class (that will replace the previous one):

As you can see, it still has the same overall structure and works the same way as it did before. We simply removed all usage of the CustomEventData type and "merged" the trigger/listeners functions using overloads.

Now, we need to update the various scripts that used events to match this new system. Basically, we’ll have to:

  • replace all occurrences of the TriggerTypedEvent() (resp. AddTypedListener(), RemoveTypedListener()) method with the simple TriggerEvent() (resp. AddListener(), RemoveListener()) function
  • replace any occurrence of CustomEventData instances with a basic object variable and then, in our listener callback functions, cast the received data into the proper type so the compiler knows what actual type the variable boils down to in the end.

Changes in the UIManager

In the UIManager, we need to change the listeners declaration and their callback functions - the following snippet of code shows all the modified functions:

Changes in the BuildingButton

In the BuildingButton, only the OnPointerEnter() function changes:

Changes in the UnitManager

In the UnitManager, we also have a couple of typed events that have to be adapted:

Conclusion

And that’s it! We can now remove completely the CustomEventData class and we won't have to worry about adding/removing/modifying the fields of this struct in the future!

This was a really quick interlude, just to remove this small thorn in our side while it’s still manageable :)

⬅️ Tutorial #10: Moving the camera| TOC | Tutorial #11: Adding a day-and-night cycle ➡️

📕 Get the ebook and bonus material on Gumroad! 🚀 Find the code of this tutorial series on my Github!

If you liked this article, you can find more blog posts about tech, AI and programming on my website :)

Csharp
Games
Unity
Tutorial
Development
Recommended from ReadMedium