How to Efficiently Query and Use Component-Based Nodes in Godot?

Yes, I completely agree with your point. My main concern right now is how to implement this binding layer elegantly.

For example, in my current game, I have trees, stones, animals, and mechanisms. Each entity is composed of a set of relatively independent functional nodes, with the root node responsible for binding these functional nodes together. Since this binding functionality is very generic - just managing, registering, and finding these components - it should only need one set of code inheriting from Node.

However, since these objects have different base classes (trees are StaticBody3D, animals are CharacterBody3D, mechanisms are RigidBody3D), it’s difficult to reuse this binding code across these objects, and we might need to copy-paste it many times (which is neither safe nor elegant).

But I’m very happy that after extensive research, I discovered that by using the node’s meta data, we can bypass this binding layer entirely, which feels great. Here’s a simple example:

Component usage example

Property component

class_name PropertyComponent:
extends Node
@export var health:int=0
func _ready():
get_parent().set_meta(“PropertyComponent”,self)
func hurt(amount: float) → void:
health -= amount
if health<0:
die()
func die():
pass

Damage component

class_name DamageableComponent:
extends Area3D
var property_com:PropertyComponent
func _ready():
get_parent().set_meta(“DamageableComponent”,self)
func get_property_com():
return get_parent().get_meta(“PropertyComponent”,null)
func take_damage(amount):
var propertycom=get_property_com()
if not propertycom:
printerr(“warning:no property com”)
return
propertycom.hurt(amount)

No need to write binding code in objects anymore, avoiding the issues of GDScript not supporting multiple inheritance and different base classes

If components have interdependencies, they can be exposed via export and connected in the editor

class_name PlantTree:
extends StaticBody3D

Components can be directly added as child nodes in the scene tree, plug and play

Can also have PlantTree-specific code

class_name Animal:
extends CharacterBody3D

PropertyComponent

DamageableComponent

Components can be directly added as child nodes in the scene tree, plug and play

Can also have Animal-specific code

Component usage example:

For bullet hits, we can filter bodies by component type and find the damageable component

Each function call is type-safe and supports editor hints

func _on_body_entered(body:ComponentManager):
var damageable_com:DamageableComponent=body.get_meta(“DamageableComponent”,null)
if damageable_com:
damageable_com.take_damage(10)

2 Likes