Do I really need to create a Node3D when I want to create a reusable script?

Godot Version

4.2.1

Question

This is more like a conceptual question. In tutorials, I see that when wanting to add a script with generic functionality, the first thing is creating a Node3D in Godot 4 or a Spatial component in Godot 3, and then attaching a script to it. This component is part of the main object…
See here :
image
The CharacterMover is just a Node3D with a script attached to it; it doesn’t hold any in-game assets. My question is: why do I need to add this object when I just want to attach some script to the main component (Player)? Is it not a waste of resources? Are there better ways?

Good question!

In my view: The way that Godot is designed is that each Node in Godot has a set task. This is the engine’s philosophy. Because if this, each Node can only have one script attached to it at a time. Scripts also cannot exist without a node. This is why developers have to create some sort of node for the script.

Is it a waste of resources? Well, slightly. Since the 3D node has a position, Godot needs to keep track of this and other properties, that will use up space in memory, but overall it’s a very, very small waste. Personally I would use a Node instead, as it requires less detail.

If anyone reads this and sees any mistakes I’ve made, please let me know!

3 Likes

Well put! One small correction is that you don’t need to extend Node ( or any of its children ) in a script necessarily.

You can also extend Object, RefCounted, Resource, etc., but then you would need to instantiate them from another script, you can’t add them to a scene in the editor, since they’re not a node.

One use case for this that I like to use is a Lock class. It can be locked multiple times, and is only unlocked when everyone who locked it unlocks. I use this for locking player input while interacting with menus, or locking other parts of the UI while interacting with something that requires exclusive focus.

It doesn’t make sense being a separate node, but it works well as a member of some other nodes that need some kind of locking functionality.

2 Likes

I can offer a third component to this,

if the script requires to be run automatically periodically (like the _process function) yo need to extend a node class. If you just have some state that needs to be stored and helper functions extend the object or resource class.

If you need processing, and you don’t want to add the node in the editor add a class_name to the script. And in your root node scene call addchild(MyClass.new()). Object and resource classes should also work like this of you give them a class_name, but you can’t add them as children.

Keep in mind this only works if your class doesn’t have children, i.e. it can’t be a scene.

You could add a “fake” periodic function in an object class and call it from the parent reference.

Extends RigidBody3D
@onready var my_class : MyClass = MyClass.new()

Func _process(delta):
  my_class.my_process(delta)
  ...
3 Likes

I agree with all the previous responses, mainly just want to point out that there’s also a good page in the docs about this:

My general rule of thumb is that if I want to be able to add the component to the scene tree in the editor, I extend Node, and if I don’t care about that, I extend Resource. The docs give more specifics and also more options.

I’m kind of surprised your example extends Node3D rather than just Node if it’s just there to add a script. Node doesn’t have a position though, so if the script’s behavior depends on position that’s one reason why Node3D might have been chosen.

3 Likes