Thanks a ton for the extensive information. I now understand your problem a lot better. The following sections will tackle the problems that you’ve outlined in your recent posts.
Using and configuring prefabs (scenes)
For software such as games, it is convenient to have access to a blueprint for a complex prefabricated object (a.k.a prefab); an object whose configuration is predetermined ahead of time. With prefabs, you can instantiate complex objects on a whim without needing to build the object through code.
Prefabs also benefit your workflow as they can be easily copied and reused in the game engine’s editor. This is also nice for the maintainability of your project as any changes to the prefab will be automatically replicated to any instances of that prefab.
In Godot, the complexity within a prefab instance is hidden away; you don’t have access to children of the prefab. As you have noted, this is an issue if you want to configure each instance in a unique way.
However, these restrictions are entirely by design. As an example, scripts will often pack away the complexity of their functionality and only expose the parameters, variables, and functions needed to control its behaviour – it’s called encapsulation. The same principle should also apply to your packed scenes.
With the way you have built your player prefab, you have created a harsh semantic line between the _player, _moveableObject, and _hittableObject nodes. Similarly, your main scene will only have direct editor access to the root of your Player prefab. As far as the main scene is concerned, the player object is one holistic object.
I hope it’s clear that the nodes are only hidden in the editor. The nodes are just as accessible through code as any other. It’s purely to communicate the prefabricated/encapsulated nature of prefabs.
Inheritance vs composition
You mention that there are a few ways to go about using a script’s variables and methods:
- Through a reference to the node/script
- Exported variable
- Through a reference retrieved at runtime (e.g. via
get_node())
- Through inheritance (i.e. extending a specific class)
The first two options listed here use composition. Using composition means creating a system that functions on a set of sub-systems i.e. a class that makes use of other classes via reference. On the other hand, inheritance allows you to create classes that are derived from a base class i.e. a class on top of another class.
The two concepts may sound similar but they each have contexts in which one is better than the other. As an example, a character controller for a specific game will likely inherit from a pre-existing controller to make itself function within the surrounding ecosystem while adding (extending) functionality that makes this new specialized class capable of new things.
Inheritance example:
PlayerController-inherits-CharacterBody3D
The key principle to follow when using inheritance is: the specialized class should never offer functionality beyond the nature of the base class. The CharacterBody3D class provides functionality for easy-to-use 3D platformer movement. Similarly, the PlayerController class should provide movement-related functionality – or more precisely, it should add this functionality.
If you wanted to add health, you should add it with composition instead of inheritance as a “Player Controller” should not manage health-related systems. An example of how health can be added with composition is described in the section below.
A prefab example (with health)
Here is a concrete example of a prefab that makes use of composition to create a vehicle object that has: health, damage, and physics joints.
Pay special attention to the root node, Vehicle (4-wheeled), and the grey nodes in the bottom, Health and DamageSource.
The root node has a VehicleController script attached to it which controls the wheel joints named Spring (__). The VehicleController script uses inheritance as it is derived from the RigidBody3D native class. This is important since the vehicle should be able to interface with Godot’s physics system. The child nodes also rely on the root being a physics object.
The grey nodes are incorporated into the object through composition. The health, damage, and vehicle controller node are not directly aware of one another but will still function through the use of signals.
When the object is hit (the rigidbody), the health node is found at run-time and damage is applied. When the health node is damaged, it send out a “health changed” signal. Any nodes that are connected to that signal with respond accordingly and can do so uniquely.
The opposite setup is used for the damage node. The damage node will dynamically get a reference to the parent, determine its type, and connect to any relevant signals (e.g. _on_body_entered).
Crucially, this use of composition will allow me to add/remove health and damage nodes to any object that I desire – the nodes themselves will do the work for me (although I do have to connect nodes to the health’s signal).
Final remarks
I am still wondering why you felt the need to make a prefab for the MoveableObject and HittableObject. Unless you intend for other prefabs (e.g. enemy) to share the same configuration for these two nodes, there is no need for nesting prefabs like you’ve done.
The reason you should use prefabs is to make your workflow easier. Therefore, ask yourself why you’re making them. Is it because:
- An object shares a 3D model configuration with another object?
- An object is too complex to be created step-by-step at runtime?
- The object functions as a modular piece for a more complicated object?
I guess my specific question is: why are the MoveableObject and HittableObject nodes not a direct part of the Player prefab? Surely your player will be different from your enemy objects – at least in terms of graphics and collision boxes.
You can do it, but you have to edit the packed scene, not the instance of it.
This is not necessarily an issue and it depends on the system you’re building. Hopefully the example I provided gave you one way of avoiding excessive referencing.
I’m not sure what you mean by avoiding copying and pasting code into an object. Do you mean attaching a script to a node, or?
I hope I covered most of the worries and doubts you have regarding this issue. Feel free to ask any further questions.

