Which Node is best to choose as a root for entity base class in 3D?

Godot Version

4.5.1 stable

Question

Hello!
I’m fairly new to programming, but I’m really interested in creating hybrid “architecture” of Inheritance and Components inside Godot. And I’m stuck at the very start. I want to create something like base class on which I will build every other classes by attaching component to them.

I can’t figure out what to choose as a root of this base class. If I use just Node, then it’s inconvenient to move the entities around in viewport. If I use CharacterBody3D, then something like a chest or tree has the ability to move, which seems wrong. Then there’s Node3D, which seems the most logical, but I’m a bit concerned with it having position, it means that my CharacterBody3D will move, but it’s root will stay at fixed position and it also seems like an issue.

I’m sorry if it is a dummy question, I looked online, looked in docs and even tried asking AI, but couldn’t figure out what to choose and if it is a good approach at all. Thanks!

The topic is inheritance vs. composition and finding a good mix between them.
Concept: imagine having an Enemy class. Do you need a subclass for an AirborneEnemy or can you attach a child node that makes it airborne?

How You Can Easily Make Your Code Simpler in Godot 4

Node3D is a good point to start with (if all your entities need a position; your players CharacterBody3D is just a specialized Node3D, so that’s fine).

I use both inheritance and components. Granted, I work in 2D, but the concepts are the same.

I use CharacterBody2D as the root for all my character classes. It inherits from Node2D, so everything a Node2D can do a Character can do as well.

Most of the components I create inherit from just Node2D so they can interact with the game world. The ones that don’t interact with the world tend to inherit from Node.

When I have a component that relies on a specific control, like the shader on a character sprite, I use an _init statement to make sure the component has a reference to the control that is being modified. For example:

class HumanDeath extends ShaderShared:
	func _init(new_sprite: Sprite2D) -> void:
	super(new_sprite)
	shader = ShadersMap.HumanShaders.DEATH

The basic guideline I follow is inheritance is for defining a group of things (i.e what do all humans have in common?) while components are for handling a specific task (i.e. how do I set up that shader?)

The best is not to have the Entity class.

Can you elaborate please?