godot: When removing a TileMap node (or its parent), remove_child method sometimes causes a crash.
Edit: This comment is outdated / misleading. The core issue is TileMaps and physics processing - see below.
Issue:
I have a situation where I need to switch a node between being “active” and “inactive” - so that when inactive (or disabled) its script and processes etc. stop running. However, using remove_child()
will (almost always) cause the whole game/engine to crash (at least on Win10) - tried using call_deferred
, set_process_internal(false)
and waiting some idle_frames too. Using queue_free()
, there will not be a crash but the node cannot be added back to the tree (because it’s not in memory anymore).
Workaround hacks:
- My workaround now is to hold the original node in memory, and when I want to insert it, I duplicate the node and insert that duplicate - upon “disabling” the node, I call queue_free() on the duplicate. As is clear, this is not optimal in any sense (especially if a very complex node with a lot of kids), and it also brings other problems (eg. with AnimationPlayers inside the duplicated node - at least autoplay won’t trigger, didn’t check what the problem exactly is yet).
- I know one other kind of workaround is to save the original node as a PackedScene and then just load and instance it again, but it is not the same as remove_child + add_child (which holds all the node’s properties in memory). More importantly, this method also adds other complications - such as instead of saving some scene (eg. some place in a world) should make a “export mini scenes” functionality (eg. a dock tool), and handle all its special cases (tried it initially), as well as keeping book of all the miniscenes after renaming the main scene etc.
Suggestion: I think either of the below two suggestions would fix this “problem”:
- A
queue_remove_child()
or similar method - would function likequeue_free()
but only removes from the tree, not from memory. - A
disable_node()
method, which would stop the scripts and processes etc. from running - or at least so, that remove_child could be called without crash after this. … Or maybe acall_queued()
method…? (I know “disabling node” has been discussed - but didn’t found a solution in the discussions that would work in my case.)
About this issue
- Original URL
- State: open
- Created 6 years ago
- Comments: 21 (7 by maintainers)
I can reprocude the error.
Also did it successfully in a minimal reproduction project: bug_remove_child_updated2.zip
Edit: Updated Project with more debug prints.
The Project consists of:
I’m unsure here if the navigation node is needed and was just rebuilding it from my project where I encounter this error.
The player will
move_and_slides
along the x-axis and will collide with 2 inherent Node. First one will float above the ground, while the second overlaps the ground. The nodes’ area eventbodyEntered
will emits a signal on_on_Area_Body_entered
to the player, which will remove the child from the root scene withget_node("/root/Main").remove_child(body)
.The player passes the first one and the Object disappears. When hitting the last one the application crashes. Even former debug prints will be obmitted.
Please tell me, if and how I can provide more detailed logs, if needed 😃
I have the same issue. It happens when a a kinematicbody2d with a collision area is overlapping another area and then I try to remove it from there scene with get_tree().current_scene.remove_child(kinematicbody2d_node). It doesn’t crash my game, just prints an error. My current hack-around is to move the object inside a _physics_process so that it isn’t overlapping the area and only then remove it from the scene. Its quite a hack and is quite annoying to deal with.