Godot
Godot 4's been out for a while now and is in a bit more of a stable place than it was when it was first released. I have a bit of experience with Godot, but with the Brackey's YouTube channel releasing a general overview of Godot and a video on GDScript, Godot's scripting language, I figured it was a good time to check back in with the engine and write down my thoughts.
The What and Why of Godot
Godot is a free and open-source game engine. The source is available on GitHub, so anyone can read the code and contribute to the project. This is a big deal for many developers, since it means that they can see how the engine works and fully own their projects. This is in contrast to engines like Unity and Unreal, which are not fully open-source, and require developers to pay royalties after a certain amount of revenue is made.
Unity recently announced that they would be collecting a "runtime fee", which is a fee that developers would need to pay for each install of the game. They walked back significant parts of this policy after a significant backlash, but many developers have vowed to switch to alternatives like Godot after the debacle.
Godot is not as fully-featured as Unity or Unreal, but it is a very capable engine that can be used to make both 2D and 3D games. It has it's own scripting language and, importantly, comes with an editor, something many open-source engines lack. This makes it simpler for developers used to the Unity or Unreal workflow to get started.
How Godot Works
There are a few important concepts to understand when working with Godot:
- Nodes and Scenes
- GDScript
- Signals
- Resources
Nodes and Scenes
Godot works off of "Nodes". Nodes are the building blocks of everything, and can be placed into a tree-like structure, with a single node at the root but many children, grandchildren etc. Each node inherits from a base class, and can have children nodes. Each node can also have a single script attached to it.
Godot comes with lots of built-in nodes, like Node2D, Sprite2D, Camera2D. These built-in nodes can be used to create more complex node hierarchies, which can then be saved as a "Scene". In Godot, a Scene is a reusable collection of nodes in a particular hierarchy. Scenes can be loaded into other scenes, and can be saved as a "PackedScene", which can then be loaded on the fly and instanced multiple times in the editor or at runtime.
I won't go much deeper into the specifics of how nodes work here, other than to say that I find the node system to be fairly intuitive, but also limiting. It's a bit like working with Unity's GameObject system, but with more restrictions, especially around scripting, as nodes may only have a single script attached. This means that you need to do a bit more planning around how your scenes are structured ahead of time, or you may end up with quite a mess of nodes on your hands.
If you'd like more information on how nodes and scenes work in Godot, I'd recommend checking out that first Brackey's tutorial, the intro to scenes/nodes in the docs, or this video going through every built-in node in Godot
GDScript
GDScript is the scripting language that comes with Godot. It's a dynamically typed language that is somewhat similar to Python, and allows progressive static typing. It's pretty simple to learn, but has some quirks and limitations that can make it a bit frustrating to work with at times.
In GDScript, scripts are files that are attached to nodes, and represent the equivalent of a class in other languages.
This is implicit, but if you need to reference the type of the script, you can use the class_name
keyword
to specify the type of the script. You can still create internal classes for a script, but these are not accessible
outside of the script.
There are no namespaces in GDScript, so everything just goes into the global namespace. I really don't like this,
but this can be mitigated by giving the class_name
a prefix which acts like a namespace. not ideal, but it works.
You can also use the extends
keyword to inherit from other scripts, which gives you access to the parent's
methods and properties. This is a pretty standard feature in most languages that support inheritance. When you define
a new node type using a script, it becomes available in the editor as a new node type, which is pretty cool.
Signals
Signals are Godot's first-class implementation of the observer pattern. They allow you to emit a signal from one node which other nodes can then subscribe to. These subscriptions can be set up in the editor, but I've found it easier to do it in code, as it's more explicit and easier to see what's going on.
Setting these up in code requires a reference to the node emitting the signal in the listener node's script, which
can be a bit of a pain. In the Brackey's tutorials I mentioned, this is done by setting up a node reference in the
script, but I prefer using the @export
annotation to expose a node reference in the editor, as it's not as brittle
as a relative path.
Best practice is the so-called "call down, signal up" pattern, where parent nodes are responsible for calling methods on their children and children nodes are responsible for emitting signals that their parents can listen to. This pattern is explained more in this article, which also gets a shout-out in the linked Brackey's video on GDScript.
Resources
If you've spent much time with Unity, you might be familiar with the ScriptableObject
, a class that allows you to
serialize structured data and then reference it from other parts of the project. Resources are Godot's equivalent.
These allow you to define enemy types, in-game items, NPCs, Dialogues, etc. as pure data and have them be loaded into
the game at runtime. Resources are also class-based, so you can define behaviours inside your resource definition,
another feature that is similar to Unity's ScriptableObject
.
Under the hood, the built-in godot nodes use resources to define their properties, so you can think of resources as a way to configure the nodes which hold the game's logic.
I haven't worked with custom resources as much as I'd like, but if they're half as powerful as ScriptableObject
s,
they'll be an invaluable part of the Godot toolbelt. You can see
this talk for some examples of how useful this type of object can be.
The Editor
Godot comes with a pretty robust editor, complete with a scene view and a built-in script editor. I'd really prefer to use an external editor, but the built-in editor is pretty good, and has some nice features like code folding and light intellisense. I should note that you can use an external editor with Godot, but I haven't tried it yet.
The Godot Editor
Other neat features in Godot/the editor (in no particular order) are:
- The ability to create custom editor plugins
- The docs are built in, so cmd (or ctrl on Windows) + clicking on a method or class name will take you to the docs
- Each node type has a unique icon and is roughly color coded (eg all 3D Nodes are red, while 2D ones are blue)
- The UI system works a lot like SwiftUI's view modifiers, which I'm pretty familiar with at this point
- The editor switches to display the scene hierarchy for the running game when you hit play. It's not as nice as Unity's editor/runtime connection, but it's close
- The Gizmos system is pretty nice, and you can easily render gizmos in a debug build, giving you a look at physics shapes, raycasts, etc. at runtime
- The editor has a nice and clean design. It feels...cozy, if that makes sense
Wrapping Up
I'm certainly no expert in Godot after this week, but I could probably knock out a game jam game without too much trouble. Other things I'd like to look into for Godot are:
- Shaders: Godot has it's own shader language, which is kind-of annoying
- Rendering: Godot doesn't have as customizable a renderer as Unity or Unreal. It comes with a "Forward+" renderer, which allows some deferred rendering techniques to be used
- Plugins: There are some impressive plugins, like Dialogic, for managing in-game dialogues. I'd like to learn how to make my own
I may build out some simple AI systems in Godot to test out some concepts, but I don't have solid plans for any project in particular yet. Guess I'll have to wait and see what jumps out as an interesting project.
See you next week!