Can you change a Node's type from a script at runtime?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By MadTinkerer

In the Godot editor, changing a Node’s type is as easy as right-clicking on it and changing it’s type. If it’s script extends from the class that is the type of the original node, you need to change it, but if it inherits from a class that both types inherit from, you don’t need to change the script’s extend constant.

So: assuming I’ve already created a script that is compatible with two different types of nodes, is there a way to switch between those node types at runtime? For example: creating a VBoxContainer that changes itself into an HBoxContainer and back again? As long as said VBoxContainer’s script inherits from BoxContainer, it seems like there should be a way.

I couldn’t find a change_type() or change_class() function so I’ve been fiddling with replace_by() and get_class() and so far I’ve been able to get either nothing to happen or crashing Godot.

:bust_in_silhouette: Reply From: Ev1lbl0w

The editor internally calls replace_by() to change the node’s type, so that should’ve work fine. Can you post the code you’re using to try changing the node’s type?

Here’s the code (this is attached to a VBoxContainer with a few ColorRects inside so i can see if it actually changes or not):

tool
extends BoxContainer

export var isHBox := true setget SetBoxOrientation

var HBoxClass = HBoxContainer.new()
var VBoxClass = VBoxContainer.new()

func SetBoxOrientation(orientation):
	if orientation:
		replace_by(HBoxClass.get_class(), true)
	else:
		replace_by(VBoxClass.get_class(), true)

func _process(delta: float) -> void:
	if Input.is_action_just_pressed("ui_up"):
		SetBoxOrientation(!isHBox)

MadTinkerer | 2021-08-26 20:07

Don’t try to actually use that code BTW, unless you’re trying to make Godot crash. sash-rc already let me know that it’s not going to work in principle.

MadTinkerer | 2021-08-27 16:02

:bust_in_silhouette: Reply From: sash-rc

Node type in runtime: no.

Editor is just creates new node, copies applicable properties and then deletes old one.

If you want to operate on multiple classes that are sharing common base class, just write your code for base class and it will work for inherited types.

func use_container(container : BoxContainer)
    # code compatible with just BoxContainer

use_container($HBoxContainer)
use_container($VBoxContainer)

Thank you. Potentially, what I actually wanted to do was create a scene that could act as a KinematicBody2D or a Body2D. Something sort of like “ragdolling” or a platformer character that could be launched into the air with physics and then “recover” from the state and go back to normal platforming controls. KinematicBody2D characters can interact with RigidBody2D objects, but you can’t just tell a KinematicBody2D “act like a RigidBody2D for two seconds and then act like a KinematicBody again”.

Right now I have four different scenes that all use the same script, inherited from CollisionObject2D. The only difference between them is that the root node of each scene is either Area2D or one of the Body2D types. While I used the BoxContainer nodes to test my idea, ultimately I was thinking that maybe I could create a single “Actor2D” that could switch at run-time between the four different nodes that inherit from CollisionObject2D.

Knowing that this specific method is impossible just saved me hours, if not days, of work. But I’m sure I’ll figure something else out.

MadTinkerer | 2021-08-26 20:29

Just to add some clarity: you can still perform these steps (of node re-creation) by yourself, but again it’s up to you to take care about all its dependencies, like children, properties, signals, and possible references from outer scope.

sash-rc | 2021-08-26 21:23

Yep, and node re-creation certainly has it’s place, but for what I’m trying to do node re-creation is not exactly what I want. What I’m trying to do is more of a state change, and I was just trying to do it incorrectly.

MadTinkerer | 2021-08-27 16:01