0 votes

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?

in Engine by (557 points)

2 Answers

0 votes
Best answer

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.

by (557 points)
+1 vote

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.

by (28,744 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.