Reasons for a solo dev to love Godot Engine
Sun, 21 Aug 2022 20:22:29 +0100
Godot 3.5 2D editor running my word puzzle game Syllabits
Godot 3.5 2D editor running my word puzzle game Syllabits

Godot is fun

Godot Engine is a game engine that has made me rediscover the fun of making games. As a hobby, I’ve been creating games and apps for mobile for 10 years, and I only recently started using Godot.

Although I tried using game engines before, I always ended up programming things from “scratch” (using Apple’s Xcode and their Kits). Don’t get me wrong, game engines are good and a lot of hard work has been put in all of them. But they can be overwhelming for one-man projects.

In this article I’m going to compare some of the aspects I find important for my projects, and why I ended up using Godot. Every project is different, so I’m sure you will have your reasons for a different choice.

A bit of self-introduction

I’m not going to do a thorough comparison of current game engines. There are plenty of resources online talking about their renderers and their performance. Instead, I’m going to speak from my own experience, focused on some aspects that I will describe in the next section.

Professionally, I worked for 4 years implementing graphics techniques for Fox Engine, an in-house engine for Kojima Productions (when it was still part of Konami). The biggest amount of work I did was on deferred rendering and rendering of indirect lighting through spherical harmonics (check my Mac app Harmonikr), but I also implemented basic stuff like the sky simulator, 2D sprites, the VFX system, shadows, depth-of-field, motion blur, damage shaders, and all kinds of graphics stuff.

Detail of Japanese magazine CGWorld #206, with an in-depth article about Fox Engine
Detail of Japanese magazine CGWorld #206, with an in-depth article about Fox Engine

After that, I worked a couple of years using Unity in 2.5D games for mobile, in a different company. The scale was much smaller, so I worked in all aspects of the game, even the backend. But the greatest amount of work was on optimization (see my Unite Japan 2013 presentation).

Then, I moved to the UK and started working again making console games. I used Unreal Engine 4, and also an in-house game engine used in Disney’s Infinity. I worked mostly in optimizing graphics and fixing UE4 lighting bugs.

Currently, I’m out of the games industry, but I still do rendering work, mostly server side, at Metail. We had our own renderer, but more recently we use V-Ray cloud rendering.

In my free time, I’ve been making small games and apps. Mostly word puzzle games for iOS, using Apple’s SpriteKit. But I also started a pet graphics engine, Vid Engine, using Apple’s Metal graphics API. I started it mostly to learn about Metal, but I also released an app made with it, Palettist.

This year I started using Godot and I ported one of my word puzzle games to Android with it, Syllabits (on the cover image).

Reasons for not using a game engine

For me, the main reason to use a game engine is the editor and all the libraries you get with it (graphics, physics, sound, etc.). But if you are working on a simple 2D game, perhaps the overhead of adding an engine is too much for what you are getting from it.

These are some of the issues I see with game engines:

  • Time to get started. Do you have to register and get a license? Do you have to download lots of stuff? How long does it take to install? If it’s source-based, you may also need to compile the editor yourself.
  • Space. Does it fit in my laptop? Do I still have space for the build tools? In my case, I need Xcode to build for iOS, and that takes a lot of space already if you add simulators. Using Xcode directly is the most space-efficient solution.
  • Binary size. How much overhead does the engine add? If you are creating a 2D game, you can try creating a simple stage with a few sprites and compare its final binary size in iOS with respect to the same project created in SpriteKit with Xcode.
  • Optimization. Are there proper tools to measure performance? And how easy it is to optimize? When I worked with Unity, I used Unity tools to evaluate CPU and memory performance, but there were memory leaks on Android once compiled. The reason was a bug in Mono very difficult to find. I had to reverse-compile the C# bytecode to find out that static variables were created by the compiler inside lambda functions. And for graphics, instead of the editor, the best thing was to make the iOS build and use Xcode frame capture tool. There I could see there were unnecessary textures from the engine, for instance, although there was no easy way to get rid of those from the editor.
  • Deprecation problems and rejection issues. How easy is it to update to the latest release guidelines for the platform you are targeting? If you try to release some feature that has been deprecated, Apple may reject it. More often than not, you get hundreds of warnings in the iOS build which tend to be a symptom that the Engine is not up-to-date with the latest build tools. But it’s very difficult to address those by yourself. Whereas if I had written the game directly in Xcode, it would have been really easy to update.
  • Access to platform native features and latest API. If you want to try the new things Apple announces in the WWDC, your best option is to develop natively on the platform. For instance, in Palettist I was exploring the display-P3 color space, but many engines still do not have explicit support for it (not even Apple’s own SpriteKit).
  • The editor doesn’t really make things easier. The game editor may be useful to create a prototype of a game, but for the final game you may want to script things out, like the stage creation. Specially for puzzle games, it will save you many clicks if you create the stages from code. If my stages are created from a script, I may as well create them in Xcode with Swift.
  • Not source-control friendly. Are the project files readable? Can you diff the changes? Unity has a source-control friendly mode, but still the files are quite big and it’s difficult to make much sense out from them.
  • Scripting doesn’t really save time. If I have to choose between C++ and C#, I would rather choose C# for scripting, because there’s nothing as difficult to debug as C++ build errors from templated functions from an obscure engine code you haven’t created. However, often C# can’t be debugged properly because of poor editors for Mac that fail to connect with the editor. On the other hand, Swift is built natively in Xcode, so debugging and optimizing Swift code is much smoother.

For all those reasons, I ended up programming my apps and games natively in Xcode. It can also be summarized with just 2 words: less frustration.

Why I like Godot

Godot doesn’t address all the issues I mentioned above. For instance, you can’t create any iOS native UI with it. It comes with its own 2D UI elements that may not abide by Apple’s design rules or guidelines. There are modules to give you access to certain features like leaderboards, but you are usually better off working natively for those.

However, some other aspects are really a joy:

  • a very small download,
  • no install,
  • an easy-to-use editor with properties that can be easily added from script,
  • tiny readable project files that can be even edited by hand without breaking things,
  • a very smart scene object inheritance system,
  • And a python-like scripting language, GDScript, which is very well integrated with the editor, making debugging and prototyping fun at last.

I will compare some of these aspects with Unity, because it’s a big player for mobile games and because it’s pre-compiled like Godot, and with Open 3D Engine (O3DE, branched from Amazon Lumberyard). O3DE is source-based like Unreal Engine, but it’s also Open Source like Godot. O3DE is currently not available for macOS (a major blocker!), so I’ll be using one of Lumberyard’s latest builds with macOS support. Also, I will add some notes about Lens Studio, an engine to create AR lenses for Snapchat, which can also be used to create small games. Lens Studio is quite compact and therefore comparable to Godot in a couple of aspects.

Godot vs Unity vs O3DE vs Lens Studio

My base comparison of game engines for solo development
My base comparison of game engines for solo development

See the table above for a quick summary.

Let’s look first at the space that you need for installation, ignoring other development tools that you may need for building the actual game (Xcode or Android Studio). The worst offenders are source-based engines like O3DE/Lumberyard: more than 40GB! The minimal install was so big it wouldn’t fit in my laptop and I had to carry an external drive to use it.

The download time is of course bad when the space it requires is so big… Lumberyard has to download many dependencies which also creates many files on disk. Handling that many files is also slow. If we add the installation and build times, the total time before you can actually start using it can be several hours. The build may contain errors as well and you have to figure out how to resolve them.

The project files are mostly source-control friendly for most engines, except for Lens Studio, which uses big binary data files. The main project file is in plain JSON, but it is not very readable so if you modify it by hand it may break easily. Lumberyard uses JSON for the project files, and XML for the prefabs. Unity uses YAML for their config files, metadata, and prefabs. And Godot uses GDScript-looking plain text files for project files and scene files, which are very human-readable.

I found it very easy to resolve conflicts in Godot or to modify the scene files directly in a text editor. In fact, I edited all the properties for the stages of my game Syllabits directly in Visual Studio Code (there are plugins for it, with syntax highlighting and connection to the editor). I created a template stage in the Godot editor, and then created copies that inherit from it and typed in the changes in VS Code. For instance, in the game I have a panel with a set of syllables. The scene file for a given stage looks like the one below, where you can immediately see that I’ve picked a different set of syllables for this stage:

Snippet of Godot Scene file of one of the stages of Syllabits
Snippet of Godot Scene file of one of the stages of Syllabits

This segues nicely into the topic of object reusability and prefabs. Except for Godot, all engines use prefabs for reusability. The idea of a prefab is that you create a template asset, configured with everything you need, and then you create instances of that prefab in your game. It is a great concept, but if the prefab breaks after an update, I find it quite hard to figure out what happened. If the prefab points to some component that doesn’t exists anymore, it just appears as “unknown”, and you are left clueless. Also, after you fix the prefab, you will probably need to recreate all the instances, and that means remembering all the settings you had for all of them. In Unity you may need to install a previous version of the engine, open the prefab, and take screenshots of the interesting properties. In Lens Studio I also end up taking screenshots of all the property panels. It is really time-consuming. Having the prefabs in a human-readable form helps a bit, but unless you are comfortable by editing it by hand, you still have to go to the editor to do the dirty job.

In comparison, Godot scene files are based on inheritance. As with the Syllabits example, I can have a “template” scene file where all my stages inherit from, and then I just override whatever needs to be customized in that stage. It can be just 4 lines, as above. Those tiny files are very readable and I’m confident I won’t break anything if changing it by hand. Also, if the scene I’m inheriting from has gone missing, I can’t simply create a new one with the same name and I don’t need to recreate all the other scenes that inherit from it.

The way you create custom properties for your objects and make them appear in the editor is quite straightforward for all engines. But I find Godot to be really responsive and it covers all kinds of datatypes. Below there’s another example from Syllabits, with the list of properties as defined in GDScript, as they appear in the editor, and as they appear in the scene file. It’s so neat that it blows my mind 🤯

Example definition of custom properties in Godot, for Syllabits
Example definition of custom properties in Godot, for Syllabits

Publishing the game

Godot, as other engines, have separate modules that add support for different builds. O3DE doesn’t support iOS at the moment, but all of them support Android. Publishing with Lens Studio is the easiest of all. It creates lenses that run on top of Snapchat, so they can run on whatever Snapchat runs in, and you don’t have to deal with Apple or Google.

If you are publishing a native iOS or Android app, once you have a build, it is supposedly straightforward to upload it to Apple’s App Store Connect or to Google Play Console. However, as I mentioned earlier, some issues may arise that you are not in control of. For instance, in the automatic tests that Google runs for your game, I found that Syllabits was crashing in some devices due to the audio. I had no idea how audio was implemented in Godot and why it may be crashing. Also, there was no way for me to reproduce the bug in the editor, or in my Android device to get more clues. After a couple of months, I saw there was an updated that fixed that crash, but I felt a bit helpless in the meantime.

I had other troubles implementing features like Google Play Leaderboards. Someone has created a nice plugin for Godot, but it’s the usual thing in Open-Source where projects can get outdated quite quickly. Then, you have to search for forks that may have updated it, or fix the problem yourself. But to fix the problem yourself, you need to learn a bit about Android development, which was what I was trying to avoid by using Godot in the first place.

Getting started with Godot

I found many nice tutorials on YouTube and it’s really easy to get started. There are some template projects as well, so you can start with any of those.

In my case, because I already had several games programmed in Xcode, I thought a good way to learn would be to port one of those games. That way, you can focus on learning the engine, since you don’t have to think about designing the game itself. I got the main loop of Syllabits working within one week. Then, the whole game with all its stages took me just 1 month (only working a few nights and weekends). As with other engines or with Xcode, I spent most of the time with UI things, making sure they resize nicely in different locales, and things like that. (The actual release took several months due to my struggles with Google Play Leaderboards…)

The refactoring taught me a few things I could do in the Swift version of the game as well. I find having every scene as an object that you can instance anywhere and inherit from it makes everything not only very reusable, but easy to test. The testing becomes easier because you can test each scene separately, and make changes that will be immediately reflected everywhere.

Conclusion

You can get Godot running in less than a minute and it has an editor fun to use. But not only that, the way scenes are based around inheritance and the use of Python-looking GDScript makes the whole experience very programmer-friendly.

For the type of one-man projects I create is a perfect choice. However, there are still certain limitations, common to all engines, when accessing native features of a platform and debugging on the device. For that reason, I’ve only used Godot so far to port my games to Android. But I keep the iOS version separate, programmed directly in Swift using Xcode.

Godot’s future looks exciting, with the release of Godot 4 around the corner. I want to start prototyping new games directly on it, instead of simply porting the games I already created in the past. But I have a couple of more ports to go! Porting and refactoring is a good learning exercise that I recommend as well.


◀️ Older | Newer ▶️

⏪ Previous year | Next year ⏩