[3.1 beta] How to switch node in a scene

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

I wanna let the user switch guns while playing.
I have many weapon scenes and a Player scene with a weapon as his child:
Player

  • Weapon
    I need to make a function that switches the current Weapon node with a new node (the new weapon, which is a scene), so I tried Node.replace_by, but with no luck. Is it possible with this method or am I using it wrong? Can anyone give me some examples?
:bust_in_silhouette: Reply From: Zylann

I didn’t know replace_by, but maybe that’s what you want:

var new_weapon_scene = load("res://other_weapon.tscn")
var new_weapon = new_weapon_scene.instance()

_current_weapon.replace_by(new_weapon)

Or, if not using replace_by:

var new_weapon_scene = load("res://other_weapon.tscn")
var new_weapon = new_weapon_scene.instance()

var weapon_parent = _current_weapon.get_parent()
weapon_parent.remove_child(_current_weapon)
_current_weapon.call_deferred("free")
new_weapon.name = _current_weapon.name
weapon_parent.add_child(new_weapon)
_current_weapon = new_weapon

Note that I’m assuming you don’t need to remember each weapon’s state, so this solution destroys the previous weapon and instances the new one.
If you want to memorize state, then you’ll have to not free them after removing from the tree and store them in a member variable instead (like an inventory) until the player switches back to them, instead of instancing each time.
Also, if the weapon has connected signals, you may need to disconnect/reconnect them.

:bust_in_silhouette: Reply From: DodoIta

Thank you for your answer.
I had actually tried your first approach with replace_by, but it replaces the node with nothing and I get an error because I attempt to modify a null object.
So I tried this approach:
I loaded all the new scenes as placeholders, so when I need to replace the current node I use replace_by_instance:

var cur_node = $CurrentWeapon
# I need to replace the node, so I save the info I need
var rot = cur_node.rotation
var pos = cur_node.global_position
# get the new node and remove the old one
var new_node = $NextWeapon # placeholder scene
cur_node.queue_free()
# replace the node and restore the previous state
new_node.replace_by_instance()
new_node.rotation = rot
new_node.global_position = pos

This works fine for me, the only con is that with a lot of placeholders the main scene gets quite big, but you can mitigate this by using Node containers and putting the placeholders as its children, so you can fold them in the node inspector.
I hope I’ve been clear enough.