How do you avoid "God nodes"?

Godot Version

v4.1.1.stable.official [bd6af8e0e]

Question

Consider a Rock-Paper-Scissors game. Pretty simple, the programming involves the game logic, plus keeping score etc. The rest is just the sprites, animations, UI and such. What’s the best way to avoid having one “God object” or “God node” that takes care of the whole game?

My tree is currently a single root node with a bunch of children (One “manager”, sprites, labels). The manager takes keyboard input, computes whatever it has to and passes the next sprite and label values to its siblings. It also takes care of win conditions and keeping score.

Root
– Manager
– Sprite1
– Sprite2
– Label1
– Label2

I found myself writing code like this in the Manager node and couldn’t help but wonder if there’s a better way to do this:

@onready var sprite1 = get_parent().get_node(“Sprite1”)
@onready var sprite2 = get_parent().get_node(“Sprite2”)
@onready var label1 = get_parent().get_node(“Label1”)
@onready var label2 = get_parent().get_node(“Label2”)
@onready var label3 = get_parent().get_node(“Label3”)
@onready var label4 = get_parent().get_node(“Label4”)

Then again the scope of the game is pretty small so this is manageable. I just want to follow good practices.

1 Like

The problem with get_parent().get_node() is that this breaks if you ever reparent a node. This is more resistant to breaking:

@export var label : Label = null

then assign label from the inspector.

You can now freely reparent the Label node within the scene without the rest of your code breaking.

An even fancier solution is to use signals. The labels, presumably, only ever display text. From the manager script, you can define a signal like this:

signal update_label_text(new_text : String)

Then in root, you can connect a method to the event:

@export var label : Label = null
@export var manager : Node = null

func _ready()->void:
	if manager != null:
		manager.update_label_text.connect(label.some_function_in_label_script.bind())

Now you can update the label’s text from any method within Manager by adding this line of code:

update_label_text.emit("Whatever you want")
4 Likes

Use Signals or Singletons.

3 Likes

The only reason to modularize is to support complex systems. If you write simple games there is no reason to make complicated abstractions. I.e. you dont always have to make things “good.”

The Godot docs has a pretty good starter to be successful. There should be enough breadcrumbs to learn principles and design patterns as well as how to go about using Godot.

I would say the best way to learn is to practice and fail. So take the next step and work on a slightly more complicated game. You will hopefully get stuck fail, learn, and redesign into a working solution.

2 Likes