Godot’s amazing event system

A truly decoupled event system?

This article is also available on Medium.

Recently, I decided I’d give Godot a try. I’d tested the game engine a while back, in 2015, when it had just become open-source, and I remembered an interesting but pretty rough piece of software… my fuzzy memory had placed it way below more “main-stream” engines like Unity or Unreal Engine.

But the truth is: it has evolved a lot since 🙂

And it’s no wonder why the indie game dev scene is now using it more and more – this community-driven, fully open-source and free game engine is pretty impressive, it has a bunch of nice features to match its competitors and even some that, I think, are better designed!

Of course, I still love Unity, and I don’t plan on throwing it away (or stop publishing articles about it!). Still, there is one think I found very cool when I tested Godot, and that’s their built-in event system.

What is an event system and why is it important?

What?

Events are a core element of plenty of software projects, and they’ve even given their name to a type of architectural designs: the event-driven patterns (be it for code or data).

As we’ve started to create more and more specialised tools, events have been a nice way of having them communicate together and merge into a more complex product. This can be particularly interesting in web dev, for example, when you use microservices and need them to exchange some data via event buses.

In game dev, however, you usually have just one “product”: the game itself. So you’d think you don’t really need this communication tool, right?

Wrong. Actually, modern games aren’t just one big chunk of logic that morphs around to handle everything – we are doing such high-level and multi-featured projects that we have to implement their various systems in connected but somewhat encapsulated packages inside our project.

Sure, this is not as big a barrier as having one of your systems run on another port of the computer: in theory, you can totally have the script on your little hero access a variable inside the game manager, since all the files are bundled together in the end.

However, it’s important to remember to have a robust and well-organised project structure, in order to make the addition or maintenance of features doable and pleasant. This relies on concepts, good principles, team conventions and other tools, but events are definitely a valuable one to have in mind.

Why?

Events are mostly the key to decoupling your systems: instead of having your hero’s script directly pull a specific variable from the game manager (which we call a “strong coupling” between the two systems), it’s often better to have the manager emit a message with the variable’s value and the hero’s script listen to this type of communication (this is a “weak coupling”).

This way, you don’t enforce the existence of neither: if there is no game manager, there will be no message and the hero script will simply not run this piece of logic; and if there is no hero, the game manager will send the message “in the air” but it won’t care. This can be super useful when you’re testing your game, and you don’t want to re-import a whole chain of dependencies in your test scene to make the compilation errors disappear!

Note: that’s why we say this type of events are “fire-and-forget” – once sent, the emitter doesn’t have to remember them and/or check whether anyone was there to listen.

An event system also allows you to quickly broadcast an info to several listeners at once, and easily update this list of subscribers.

Because they remove the strong dependencies between your systems, you avoid mixing up different parts of your project or leaving all variables open for the taking (and adopt better data encapsulation principles) – and of course, it makes it easier to collaborate since devs can work on each system autonomously.

For more info and an example of how to use events in C#, check out this other article I wrote 🚀

Unity events VS Godot events?

Before I say anything about events, it is important to note that no two game engines follow the exact same philosophy. Each project has its values, its own goals, its own people, and its own history. So I don’t plan on saying that one is better than the other – I love developing games with Unity, and I find Godot really fun and easy to dive in. Both have their advantages and drawbacks.

But there is one thing that, I believe, those two game engines share, and that’s the “DIY lego-blocks mantra”. Unity and Godot offer you a set of basic components you can stack together on your objects to gradually build more complex behaviours, but they don’t come with ready-made large systems like a HUD of placeholders, or a full technology tree. That’s the whole point: you’re supposed to pick from these granular bricks to build your own unique design, for your own unique game.

Note: in comparison, I’ve felt like Unreal Engine relies more on its library and pre-existing assets… it might be just my experience, but I found it quite hard to build something from scratch in UE without spending hours on it!

And of course, one of these base blocks are events.

The two engines have some built-in events (for example, when you click a button, it will emit a signal), and they allow you to define your own custom events, too. Let’s talk about both and see how Unity and Godot compare.

Built-in events

Nowadays, any game combines both 2D sprites or 3D models with UI elements. Players expect menus, and healthbars, and skill buttons, and so on (and to be honest, the days where we just used text in terminal aren’t over in some circles, but historically developers quickly decided that user interfaces were a safer bet).

This is one example where events are used a lot: when you hover an image on your screen or you click on a button, you might want something to happen. You want to assign a callback to this action so that “clicking button 1” is translated to “throwing a fireball”.

Unity and Godot allow you to do this via their built-in event system.

The cool case

For example, the Unity Button component has an onClick field on which you an add one or more listeners (i.e. the callbacks), and similarly a Godot Button node emits a “pressed” signal on click.

Both these cases give you a lot of flexibility, because you can drag in whichever listening object you want in Unity:

And you can link as many receivers as you want in Godot:

The not-so-cool case (in Unity)

However, another common problem is when you’re dealing with colliders or triggers. This a classical pattern in a video game: you put some invisible object somewhere to act as a “special area” so that, whenever the player crosses it, some logic is executed.

In Unity, turning an object into a trigger zone can be done by adding a 2D or 3D collider on it, and enabling its “Is Trigger” option:

In Godot, you have to make sure you choose the right type of node – usually, you take an Area2D or an Area, and you assign its shape in a child node:

So far, it looks like the two engines still work the same, right?

Well, here’s the big difference: in Unity, you can’t subscribe to the “on trigger enter” event from elsewhere than the object with the Collider component! In other words, I have to specifically create an AreaManager script, add it to my “Area” object, and handle the event in here.

Godot, on the other hand, allows me to catch the event on any object in my scene – it’s like the signal is emitted and floats somewhere in mid-air, ready to be listened to by anyone who’s around!

It might seem like a detail but what I really like is that it avoids these Unity moments where you created [Something]Managers on nearly all the objects in your scene just to catch one event and instantly call another script; instead, in Godot, you can make just one script on your scene manager and link all events to it to centralise your callback functions.

Custom events

Alright, but built-in events have to be quite generic to accommodate lots of games… so I get that you have to make some choices when you create a game engine.

What about custom events, then?

Even if Unity and Godot make it quite easy to add your own events, again they do this quite differently.

In Unity (and C#), you can use the UnityEngine.Events package to create your UnityEvent variables (either with or without data) and send a message. However, if you like at most tutorials on the net, and given these variables are still C# objects you have to reference to invoke them, the system implies pretty strong coupling between the emitter and the listeners.

For example, to code my little ship colour-shift like shown above, I would probably do the following:

(where Ship2DManager is added to my “Ship” sprite object, and Area2DManager is added to my “Area” collider object)

You can see the problem here: if there is no Ship2DManager instance in the scene, then the Area2DManager will crash!

Let’s be honest – we can somewhat avoid this issue by implementing a more centralised event-system (I’ve discussed this in my Unity RTS tutorial series, for example). But this is not the straight-forward way to use the UnityEvents!

Godot custom signals, on the other hand, work the same as the built-in signals. Basically, as soon as you’ve declared your signal in the object’s associated script, typically with the signal keyword in GDScript:

Then you can see your new signal in the node’s signals list:

To me, that’s a cool thing with Godot’s events: they are pretty consistent and self-autonomous. Unity events are very adaptable, don’t get me wrong – you can create diverse event systems to really match your game design. But, more often than not, what we want is what Godot gives us: a scene-global bus event with high decoupling!

Conclusion

Unity and Godot are two great game engines that have lots of features in common, and some more specific. While Unity is recognised as one of the leading main-stream game developing tool, Godot is becoming more and more famous in the indie scene.

Today, I’ve discussed more precisely their system of events, and why I found Godot’s take on it really interesting.

I hope you enjoyed this article – as usual, feel free to react in the comments, and tell me if you have other ideas of topics for Unity or Godot articles! Thanks for reading 🙂

Leave a Reply

Your email address will not be published.