Discussing Architectural Patterns in Godot after 2 years of development

@suredesm That was a brilliant and informative post. You gave me a LOT to think about.

Networking

I am really interested in the networking component you added. I’d really like to see the code for NetworkCollectibleSync in particular. I’m currently working on a game and we had to pull the networking code out once already and I’ve been trying to figure out how to make it more modular.

GraphEdit

I’m also really interested in seeing your GraphEdit code, especially your dialog stuff. I think I’ve gotten to the point with enemy AI and state machines where I’d really like to design them with a GraphEdit node. Because in the last two weeks I’ve worked on a 2D and 3D game, and I keep going over the same basic things in my code to hook everything up.

So I’m interested in your dialog system because I think it addresses a number of pain points I’ve been having with developing cutscenes and tutorials. But also because I want to see how I can adapt it to more systems.

I’ve also been an OOP purist for a long time, and using Godot has really opened my eyes to composition. Being on this forum has also helped me. Someone asked six months ago how to make a health component, and I answered by making one and walking them through it: Am I doing Components/composition right? - #3 by dragonforge-dev At the time, I was still against the idea of a health component. Last week, after using the health component in a couple games, I started work on a Health plugin that I could re-use and also tie to a bunch of different health bars.

I wanted to decouple my player UI from the player object, but also be able to reuse it for simple health bars hovering over enemies, etc.

Assert

I was using asserts for unit tests in GDScript a few years ago, but I’ve found that over time I don’t need unit tests if I throw errors in the correct places. I really liked what you said about finding the first one isn’t good enough, and how you used asserts in the find_in() function.

Collected

I had a question about this code:

signal collected(body: Node2D)

func _on_body_entered(body: Node2D) -> void:
    if not body.is_in_group(player_group):
        return
    _collect(body)   # emit collected, play pickup anim, queue_free

In the same place I would write:

func _on_body_entered(player: Player) -> void:
    player.collect()   # execute collected function on player, play pickup anim, queue_free

And I would rely on the fact that something is not a Player, it’ll throw an error and halt the game. Thus ensuring that a collectible object is only looking for things on the Player phsyics layer.

I’m curious how you got to your code. I personally avoid groups and @exported attached nodes for the same reason: I don’t want my game to fail because I forgot to make a connection that doesn’t throw a clear error.