Overriding variable defaults

Godot Version

4.4 Dev 2

Question

How can I override a parent classes default variable? Some Control types for example override the stretch type and other default values of their parent class (the basic Control Node). They are highlighted in yellow in the local documentation.

How can I make my own class which for example inherits from CharacterBody3D and has a default position of vec3(0.0, 1.0, 0.0)?

The character body is just an example, I just wanna know how to override defaults.

This is how to make a custom class:

class_name MyClassName
extends ParentClass

#script
#...
#...

I think you can’t override any defaults of a parent class. But I think that is a general thing with object oriented programming. If you want to dive deeper into object oriented programming in godot with abstract, virtual, … classes i advice you to use the .net version with c#. I hope that helps.

I do full agree with this being how inheritance works. But Godot does it themselves as seen here!

The yellow text is german, translated it means [overrides Control: true]
So I feel like when the engine gets to do stuff like this, we should too.

i think this only works with gdextension or @export-variables

How is it some through export variables?

you declare an export variable and then you can edit it in the inspector:

@export var value: int = 10

Maybe a bit late to the party, but I wanted to do the same and the only way I found to do this is to write a constructor for the child class (_init method) which does only 2 things:

  1. Call the super constructor
  2. Sets the property to the new value.

It’s a hacky solution but here you go:

@tool
class_name YourClassName extends SomeNode

func _init() -> void:
	if Engine.is_editor_hint():
		set_meta(&"_n23", 0)

func _property_can_revert(property: StringName) -> bool:
	return property in [&"prop1", &"prop2"]

func _property_get_revert(property: StringName) -> Variant:
	match property:
		&"prop1": return value1
		&"prop2": return value2
	return null

func _on_node_created():
	prop1 = property_get_revert(&"prop1")
	prop2 = property_get_revert(&"prop2")

func _notification(what: int) -> void:
	if !(Engine.is_editor_hint() && has_meta(&"_n23")):
		return
	var n23: int = get_meta(&"_n23")
	if what == NOTIFICATION_PATH_RENAMED:
		set_meta(&"_n23", n23 + 1)
		return
	remove_meta(&"_n23")
	# notes:
	# - starting with 2 NOTIFICATION_PATH_RENAMED gives the creation sequence
	# - starting with 1 NOTIFICATION_PATH_RENAMED gives the duplication sequence
	# - starting with 0 NOTIFICATION_PATH_RENAMED gives the loading sequence
	if n23 == 0:
		# node loaded
		pass
	elif n23 == 1:
		# node duplicated
		pass
	elif n23 == 2:
		# node created
		_on_node_created()

I’ll explain a bit more the code above. From my tests, it seems that:

  • “loaded“ (n23 == 0) is only triggered when the node is created from memory, so when loading a scene either at runtime or in the editor.
  • “duplicated“ (n23 == 1) is only triggered when duplicating a node in the editor.
  • “created“ (n23 == 2) is triggered by creation within the editor, and creation only.

It’s just a weird thing using the number of NOTIFICATION_PATH_RENAMED signal triggered since the node was created. But somehow it works. I won’t question it.

And the “23“ everywhere comes from the int value of NOTIFICATION_PATH_RENAMED

Then he pairs that with the regular _property_can_revert and _property_get_revert to define defaults on the fields from the parent class.

Edit 3: I just noticed that it triggers code before you even get to `_enter_tree`, so in order:

  • _init
  • _on_node_created / _on_node_duplicated / _on_node_loaded
  • _enter_tree
  • _ready