What are some good resources to learn Code Architecture in Godot?

I’ve been coding and developing small games and projects in Godot for the past two years.

One of the main obstacles was learning the engine.
Given I had a very small coding experience (a 6 month course in Java) previous these 2 years, it took a long time for “things to just click”.

Now, after that period have passed and I’ve gained experience in Godot and feel very comfortable with GDScript, I wanted to work on a bigger project (which I am currently working on.)

Now, Code Architecture is the main problem I have to face every time I sit down and work on a new feature or implementation.
It is no longer viable to just hack things and spaghetti around until something works.

Internet is filled with tutorials on Godot: “How to make X or Y”, but I was unable to find a Code Architecture course, guide, explanation, or tip that would alleviate my struggles.

The only Resource that stands out is this free tutorial/course by @Tutemic on code architecture to “learn the basics” for GODOT.
I always recommend this course because you can learn and understand just by watching it and taking notes.

I think this video alone is not enough and I’d like to keep learning… but I have never found something explained THAT thoroughly.

So it goes back to the title…

What are some good resources to learn Code Architecture in Godot?
What are some tips or tricks you have regarding the subject?

PS: I think it’d be better to stick to Godot-only resources because, well… what we’d learn would be easier to apply. But in reality, anything will do!

2 Likes

Have you read these docs from Godot Docs? It can be useful in this sense.

I have, yes.

IMO the docs are a good introduction to Godot, yes; but not to code architecture as the docs don’t delve into code architecture and any principles or how they should be applied or when.

They make youtube videos, too, if you search for GDQuest on there.

2 Likes

I know about their videos; yes!

The architecture section is a bit outdated now, since what is written is for Godot 3.x. I’ve read it a while back!

It helps a bunch though!
Last time I checked it wasn’t this filled. Good resource in general.

I’ve seen some of your comments around the forums; are you familiar with code architecture? If you are, would you mind naming some books/info I could look to learn from?

Besides watching all youtube videos that come up under “Godot design patterns” and “gdscript design patterns” etc, you really can just read any resource on game design patterns. If you know gdscript well enough, you can translate from book’s code to gdscript.

Game Programming Patterns by Robert Nystrom is a great start as far as books.

Other than that, general programming principles apply, i.e. you can just pick up any book on programming design patterns that uses a language you’re most familiar with (perhaps Python, if you want something closest to gdscript syntax). Just make sure it’s not Advanced level, if you’re just starting out with architecture/patterns.

One of the most important patterns to understand is the Model-View-Controller pattern. This will help you understand almost any software stack, as most use this pattern or a variation thereof (such as Model-View-ViewModel).

Hope this helps, and if you have trouble choosing between books, just lmk.

1 Like

For simpler general principles:

  • Always make calls top-down and never bottom-up (i.e. child should never call/know about parent, such as child scene knowing about any scene above it in the tree). So yes, while you can do get_tree().get_node() this is an automatic red flag. It’s fine for quick projects/debugging, but known as an anti-pattern (i.e. bad design). Your app (game, website, doesn’t matter) should be like a human body: arms don’t control brains; brains control arms. However, arms can send a signal to the brain (pain, touch sense, etc.).

  • Avoid changing same property from multiple places, especially within the same scene. State Machine pattern deals with this. I often have update_ui() method that I call from _ready(). _ready is for setting up STATE (am I selected? what are my properties?) and then update_ui can adjust UI based on that state (enable/disable buttons, change label font colors, etc.). This way a parent node can change state variables of this scene and then call update_ui. Or the scene itself can call update_ui from its _on_my_signal_here if it listens to some signal(s). Ofc, if the scene only has one state, I just write in _ready coz see below.

  • Don’t overcomplicate :slight_smile: Many programmers lose themselves down the rabbit hole of optimizing for perfect architecture and there are only 2 things that make good architecture: 1) resistance to bugs, and 2) maintainability. It’s a balance between those two things. Nothing else matters, especially things like “perfection” or “amazingly-architected”. The perfect code is near-bug-free code that’s easy to maintain.

  • Limit domain knowledge. I.e., each object should only know as much as it must know to operate, and (generally) no more. For example, my game has many playable characters that can be unlocked. I define character properties in a dictionary. I could add “unlocked” property to dictionary, but does a character need to know if it’s unlocked during the game? Nope. Only main menu UI needs to know if a character is unlocked to let me choose it or not. Plus, I’d have to store entire dictionary with char data to save file if that’s where I stored “unlocked” property. So instead I have:
    StringKeys singleton that defines a string key for each character. Ex: const CHAR_DAD: String = “dad”
    CharDB file that contains the dictionary with each character’s properties: const chars: Dictionary = {StringKeys.CHAR_DAD : { “name” : “Dad”, “sprite”: “sprite_path_here” } } etc
    GameSave resource (game save file) with @export var unlocked: Array[String] = [ StringKeys.ITEM_UNLOCKED_BY_DEFAULT, StringKeys.ANOTHER_ITEM_UNLOCKED_BY_DEFAULT ]

When player selects a character, I check if Game.save_file.unlocked.has(selected_char) where selected_char is, for example, StringKeys.CHAR_DAD. But now I can give string keys to other things like weapons, levels/stages, game features, etc. and just throw those keys into ‘unlocked’ array when player unlocks them. Not sure this is a great example, but I hope it shows how thinking in terms of “what does this object need to know about itself to function?” as opposed to “what are the things the game knows about this object?” helps divide responsibility, avoid spaghetti code, and allow for flexibility without introducing fragility (change smth here and smth else breaks there).

This can become a book (there are many!! haha) but figured I’d just scribbled a few key things that come to mind as I wait for this neighborhood bar to open…

8 Likes

I just made this!

I will update it as more feedback comes in. The goal is to be concise while explaining the wisdom behind the advice given.

1 Like

I’ve used Ray Wenderlich’s courses a lot when I was doing iOS programming, they are really great at explaining things at every level. The site is now rebranded as Kodeco:

They also have JS tutorials I think. But if you learn any language well, the others will be far easier, most of the concepts are the same between them.

1 Like

Did I mention this book? A book on Godot 4 is here! Learn to create a 2.5D shooter from scratch. Just updated to Godot 4.2

1 Like

Personally I think the most important bit of code architecture is to use an event-bus singleton.

It not only helps ensure calls are top-down only, but also provides a communication bridge between entitites, and helps codify the important events that occur in a game.

For my event bus in Unicopia, which is pretty much as basic as you get for non-mobile games, my event bus defines about 20 signals (e.g. level_started, level_reset, player_died, exit_unlocked, etc.) and it really helps me create levels and new types of scenes in isolation from each other.

1 Like