Using remove_child() slows down the game?

Version 3.2.3 (I think)

So I’m making an open world game and have a routine that despawns packs of enemies if you get too far away from them. It works just fine in all ways and doesn’t slow the game at all runs at 30fps or close to it.

Then I put another routine to do the same with scenery. I basically just copy-pasted the script so there’s no programming differences. However this time, when remove_child() is used, the game immediately drops to 15 fps and stays there EVEN THOUGH THE ROUTINE TO REMOVE SCENERY IS NO LONGER BEING RUN. I’ve tested this from all angles – the script is not, like adding and removing the child every turn. Also, the script doesn’t slow down the game it I # comment the add/remove_child lines. It’s accessed once a second only, just like the one that removes enemies, which doesn’t slow the game at all.

Now, the script does work. It does remove the scenery when you get far enough away. It works perfectly, except that for no reason I can find, it slows the game to half speed, and then the game stays at half speed even if the objects running the routine self-delete, or if they add_child back in. If I delay the script running, the game runs at 30fps until the script kicks in.

I even, as an experiment, replaced the scenery-despawn script (that causes slowdown) with the enemy-despawn script (which works fine), and despawning scenery STILL CAUSED SLOWDOWN.

I cannot wrap my head around what I’m doing wrong here.

The script to remove scenery is this:

func spawncheck():
dist = player_ui.dist_to_player(global_transform.origin.x, global_transform.origin.z)

if not spawned and dist < spawn_range:
	add_child(spawn_ref)
	spawned = true
if spawned and dist > spawn_range * 1.1:
	remove_child(spawn_ref)
	spawned = false

spawn_ref is just a pointer to the child to be despawned/respawned. Could it be something in the node that’s being despawned? It’s just spatials and Static Bodies.

If I had any hair, I’d be pulling it out. Has anyone seen this before?

Thx

Can you upload an MRE to test locally?

Based on what I’m reading in your code, technically it’s not remove_child() that’s slowing you down. It’s your use of add_child(). This is because remove_child() just removes things from the tree and keeps it in memory.

Having said that, the answer to your problem is to replace that remove_child(spawn_ref) call with spawn_ref.queue_free(). It will then be removed from memory and your memory leak will go away.

See, this is why it was so frustrating. The game runs at 30. Then if I use remove_child() even once, it drops to 15 and stays there. It never calls add_child(). It never calls remove_child() ever again. It just gets stuck at 15ish for… reasons?

I did test your idea of using queue_free() and reloading by instance()ing the scenery and it does seem to work without slowdown and I may go with that. It’s just… way more time consuming for me.

Thanks for your help.