I want to encapsulate and at the same time modify details in my instances

Godot Version

4.2 stable and 4.3 dev

Question

Hello, I have a question for you, thank you in advance.

In the Godot Editor I created a scene to use as a “prefab”. This is a box of non-cubic shape (with physical properties such as mass and the ability to come into contact with other bodies). I want to be able to instantiate it several times but modifying its color.

—I built my “Prefab” as follows:
This scene consists of a RigidBody3D node with two child nodes (siblings of each other), one is a MeshInstance3D, which I use with a MeshBox resource. Since I need it to have a non-cubic shape, I modified its dimensions. I did the rescaling on the resource properties (the “size” property) instead of using “scale” inside the Transform in the Node3D class. The reason for the latter is because in the next step I created a collider (a CollsionShape3D node) by going to the MESH button on the 3D view toolbar. If I used the Transform property, Godot would throw me a warning because the resulting collider would not be scaled uniformly.

—My question is the following:
I understand that it is recommended to instantiate scenes as nodes without losing encapsulation. That is, not enabling the “Editable Children” checkbox. But if I don’t enable that editing in the instance, I don’t understand how I can modify the material of my “prefab” to change the color of the instance. Specifically, I am referring to the “Surface Material Override” property of the MeshInstance3D node.

So… How can I do what I want to do?

Expose the properties or methods you want to modify in the root node of your scene.

Example using an exported property with a setter:

extends RigidBody3D


@onready var mesh_instance_3d: MeshInstance3D = $MeshInstance3D


@export var color: Color = Color.WHITE:
	set(new_color):
		color = new_color
		
		# if the node is not ready wait for it to be ready 
		# as it won't have access to the children until then
		if not node_is_ready():
			await ready
			
		# Get the active material in surface 0
		var material = mesh_instance_3d.get_active_material(0)
		
		if material is BaseMaterial3D:
			material.albedo_color = color
		elif material is ShaderMaterial:
			# this is a custom shader, you'll need to access its parameter
			pass

But remember that Materials are Resources and Resources are shared by default. You’ll need to make them unique doing any of the following:

  • Right click over it in the inspector and click on Make Unique. This will make the Resource unique in the scene but it won’t make it unique between instances of the scene.
  • Enable Local to Scene in the Resource. This will make unique the resource when instantiating the scene (if the resource is shared between nodes in the same scene the copies won’t be made unique)
  • Calling Resource.duplicate() in code. For example in your _ready() function. You’ll need to assign back the duplicated Resource.

@mrcdk Thanks for your answer. But I was asking how to do it from the EDITOR, working only visually. As I learn how to use the engine, I build some kind of “guide” to share later. I think it would be more pedagogical to postpone the introduction to writing source code a little. Is that possible?

I’ll explain to you what I’m having in mind. In other engines, like Unity, you can build an object with functionalities similar to the “prefab” that I am building, but this does NOT have a tree structure and all the relevant properties are “components” of the same object. Then one can edit those properties on each instance. And all that instantiation and editing can be done in the editor visually.

I am aware that in a complex project that is taken seriously, writing source code is inevitable. But I want, if possible, a gradual approach, an individual concept (and concern) at each step of learning

Godot is not Unity and does not follow the same philosophy or practices. Even if in Unity you add new components to modify the object you’ll need to code them first.

You can enable Editable Children on instanced scenes in the Scene dock by right clicking over the instanced scene and selecting Editable Children. You’ll be able to modify the properties of the children of that scene.

@mrcdk Yes, I know “Editable Children” checkbox. But I thought that meant breaking the encapsulation