Replace_by not working ! something is always null

Godot Version

`4.4

Question

hello,

I have a scene that has an (instance child) “weapPlr”

the parent node “skelComponent” is calls this thing “wp1_spr”

on a pickUpitem Scene. i have this inside:

@export var weapScene: PackedScene = null;
var weapInst = null;

func _ready() -> void:
	weapInst = weapScene.instantiate();

func _on_area_2d_body_entered(_body: Node2D) -> void:
	var invWeapSlot = GlobalMenu.weap_slotNone.duplicate();
	invWeapSlot.weapInst = weapInst;

when i press a button and call a func , i can get the right prints just fine:

func _setPlayerWeapon( btnNum ):
	if ( Player == null ):
		return;
	var plrWeap = Player.skel.wp1_spr;
	var weapScene = btnNum.weapInst;
	print("plrWeap: " + str(plrWeap) )
	print("weapScene: " + str(weapScene) )

print:
plrWeap: weapPlr:<Sprite2D#62042147022>
weapScene: wp_M1911:<Sprite2D#273787390245>

i can even print the stuff inside var weapScene: ?!?!?!?!?!?

func _setPlayerWeapon( btnNum ):
	if ( Player == null ):
		return;
	var plrWeap = Player.skel.wp1_spr;
	var weapScene = btnNum.weapInst;
	print("plrWeap: " + str(plrWeap) )
	print("\nweapScene1: " + str(weapScene.weapName) )
	print("\nweapScene2: " + str(weapScene.weapType) )
	print("\nweapScene3: " + str(weapScene.dmg) )

print:
plrWeap: weapPlr:<Sprite2D#62042147022>
weapScene1: m1911
weapScene2: 1
weapScene3: 20

—//–//---------

but when i try to use replace_by on plrWeap to weapScene… Nothing seems to work i get a cascade of errors ?

func _setPlayerWeapon( btnNum ):
	if ( Player == null ):
		return;
	var plrWeap = Player.skel.wp1_spr;
	var weapScene = btnNum.weapInst;
	plrWeap.replace_by(weapScene)
	plrWeap = weapScene;
	Player.weapType = 1;

i dont know what the error mean ?!
something about a costum signal i made: signal hotBarSet( invBtn, passWeapInst ) and the wp1_spr.position = weapFollow.position… iam using in another place…

is there a way to use replace_by on this scene ?

man what a ton of bs…

if i have a weapon scene in the player and want to change that weapon for another
i have to type all this code…

func _setPlayerWeapon( btnNum ):
	if ( Player == null ):
		return;
	var weapScene = btnNum.weapInst;
	
	var new_scene = weapScene;
	var old_node = Player.skel.wp1_spr;
	
	var parent = old_node.get_parent()
	var old_index = old_node.get_index()
	parent.remove_child(old_node)
	old_node.queue_free()
	
	parent.add_child(new_scene)
	parent.move_child(new_scene, old_index)
	
	Player.skel.wp1_spr = new_scene
	#Player.myWeap = new_scene
	Player._setMyWeap()

i cant just replace that node.tscn for another…

replace_by moves all children from the old node to the new one.
To add the weapon node at the same position you can use add_sibling before removing the old node. Alternatively you could also make a ‘wrapper’ node that contains the weapon. Then you can just remove and add from the wrapper node.

add_sibling, doesnt work…
it return the same error than replace_by. For some reason the parent cant access the node ?

error:

E 0:00:59:095 skel_component.gd:372 @ _ptSimplePath(): Child is not a child of this node.
<C++ Error> Condition “p_child->data.parent != this” is true.
<C++ Source> scene/main/node.cpp:465 @ move_child()
skel_component.gd:372 @ _ptSimplePath()
skel_component.gd:730 @ _physics_process()


var weapScene = null;

func _setPlayerWeapon( btnNum ):
	if ( Player == null ):
		return;
	if ( btnNum.weapInst == null ):
		print("btnNum.weapInst is null: " + str(btnNum.weapInst) )
		
		var weapNull = preload("res://weapons/none/weapPlr.tscn")
		weapScene = weapNull.instantiate()
	else:
		weapScene = btnNum.weapInst.instantiate();
	
	var old_node = Player.skel.wp1_spr;
	
	var parent = old_node.get_parent()
	var old_index = old_node.get_index()
	
	#parent.add_child(weapScene)
	#parent.move_child(weapScene, old_index)
	parent.add_sibling(weapScene) ###############<-----------------error
	
	parent.remove_child(old_node)
	old_node.queue_free()
	
	Player.skel.wp1_spr = weapScene
	Player._setMyWeap()

add_sibling and replace_by also makes the weapScene .tcsn script not firing bullets… maybe they are being spawned off screen… but the weapon parent cant access the node “Child is not a child of this node”

this should be working for add_sibling… I managed to understand what was going on, by running the game and using remote on the level scene tree. The add_sibling was being added on the skel parent

var weapScene = null;

func _setPlayerWeapon( btnNum ):
	if ( Player == null ):
		return;
	if ( btnNum.weapInst == null ):
		var weapNull = preload("res://weapons/none/weapPlr.tscn")
		weapScene = weapNull.instantiate()
	else:
		weapScene = btnNum.weapInst.instantiate();
	
	var old_node = Player.skel.wp1_spr;
	Player.skel.wp1_spr.add_sibling(weapScene)
	old_node.queue_free()
	
	Player.skel.wp1_spr = weapScene
	Player._setMyWeap()


#----//--player-script--//-------
@onready var skel = $states/skelComponent;
var myWeap;
var weapType: int = 0;
func _setMyWeap(): #--reReads-player-weap--//
	myWeap = skel.wp1_spr;
	weapType = skel.wp1_spr.weapType;

what do you mean by using ‘wrapper’ node ? making an @export var PackedScene, on the weapon scene ?

So, does this work?

If not, it’s probably because you still have the reference to the old node in wp1_spr in skel_component (you don’t show where you set it) when you are trying to move it. You get the error because you are trying to move a node with move_child that is not a child of the calling node.

With wrapper-node I mean a simple Node2D in the player. Instead of adding and removing the weapon from the player you can instead remove it from that Node2D.

it already works i added the code on the previous post… I was add_sibling to "old_node " witch was weapon parent node:
“var old_node = Player.skel.wp1_spr;”
“var parent = old_node.get_parent()”
“parent.add_sibling(weapScene)”

With wrapper-node I mean a simple Node2D in the player. Instead of adding and removing the weapon from the player you can instead remove it from that Node2D.

I did something like “wrapper-node” on my first attempt, and it didnt looked too good. Theres too many burocracy and too many var’s being passed from node to node… itemPick, to inventory slots, to inventory item selected, to player hotbarSlot…

add_sibling is the best way, you can also add mods to the weapons later on, ( if those weapons are in independent scenes ) mods like simple sprite2D nodes on top of weapon sprite2D… scopes, siliencers…laser pointer…etc…

Yes, I know. That’s why I suggested it :wink: It just wasn’t clear if it worked.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.