You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Player sets health.base_health BEFORE HealthComp initializes itself
Reality:
HealthComp _ready() ran FIRST
@onready max_health computed with base_health = 0
Setter clamped to 0
Death triggered
Scene reloaded
Loop
This was 100% predictable given the order.
LAYER 1 — SIMPLE RULES (USE THESE NOW)
If you remember nothing else, remember this:
Children _ready() runs before parent _ready()
Never compute gameplay state in @onready
Never rely on parent data inside child _ready()
If a child needs parent data → parent must call init()
@onready is for node references, not gameplay logic
These five rules will prevent 90% of Godot bugs.
LAYER 2 — ADVANCED / SCALABLE RULES
When to use _enter_tree()
Register in autoloads
Add to groups
Setup global references
Do NOT read parent data
When to use _ready()
Connect signals
Receive explicit init() calls
Final wiring
No assumptions about parents having run logic
When to use explicit init()
Component needs external data
Component must be deterministic
Component must be reusable
You care about scalability
COMMON WRONG ASSUMPTIONS (KILL THESE)
❌ Parent _ready() runs first
❌ @onready is a constructor
❌ Setters are safe during initialization
❌ Components should self-initialize
❌ Scene reload is harmless in setters
All false.
FINAL VERDICT
Godot’s load order is child-first for _ready()
This is why composition requires explicit init
Your confusion was justified
Your fix (explicit init) is mandatory, not stylistic
If you internalize this order, Godot stops feeling random
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Good question. This is not optional knowledge if you’re doing composition. I’ll be exact and mechanical.
GODOT NODE LOAD / READY ORDER (FACTUAL)
I’ll describe what actually happens, not vibes.
Assume this scene tree:
1️⃣ Scene is instantiated (NO callbacks yet)
_ready()@onreadyAt this point:
$Node2️⃣ Nodes enter the scene tree (TOP → DOWN)
Godot inserts nodes from root to leaves.
Order:
Still:
_ready()@onready3️⃣
_enter_tree()is called (TOP → DOWN)Now callbacks begin.
Order:
Important facts:
$Childworks@onreadyhas NOT run yetUse
_enter_tree()if:4️⃣
@onreadyvariables are assigned (BOTTOM → UP)This is the part most people do NOT know.
Order:
Why?
So this is safe:
Because HealthComp already exists.
5️⃣
_ready()is called (BOTTOM → UP)This is the critical one.
Order:
Children FIRST, parent LAST.
This is why your bug happened.
6️⃣ First
_process/_physics_processOnly after ALL
_ready()calls finish:_process()starts_physics_process()startsVISUAL SUMMARY (MEMORIZE THIS)
WHY YOUR HEALTH BUG HAPPENED (CONNECTED TO THIS)
You assumed:
Reality:
_ready()ran FIRST@onready max_healthcomputed with base_health = 0This was 100% predictable given the order.
LAYER 1 — SIMPLE RULES (USE THESE NOW)
If you remember nothing else, remember this:
_ready()runs before parent_ready()@onready_ready()init()@onreadyis for node references, not gameplay logicThese five rules will prevent 90% of Godot bugs.
LAYER 2 — ADVANCED / SCALABLE RULES
When to use
_enter_tree()When to use
_ready()init()callsWhen to use explicit
init()COMMON WRONG ASSUMPTIONS (KILL THESE)
❌ Parent
_ready()runs first❌
@onreadyis a constructor❌ Setters are safe during initialization
❌ Components should self-initialize
❌ Scene reload is harmless in setters
All false.
FINAL VERDICT
_ready()If you want next:
_exit_tree()Pick one.
Beta Was this translation helpful? Give feedback.
All reactions