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:

  1. 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).
  2. 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”:

  1. A queue_remove_child() or similar method - would function like queue_free() but only removes from the tree, not from memory.
  2. 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 a call_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)

Most upvoted comments

I can reprocude the error.

$> /opt/godot/godot --version
3.2.3.stable.official

$> lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 21.04
Release:	21.04
Codename:	hirsute

$> uname -a
Linux padlizsan 5.11.0-17-generic #18-Ubuntu SMP Thu May 6 20:10:11 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

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:

  • a navigation node
    • navigation mesh (baked)
    • mesh instance (ground)
      • static body
        • collision shape
  • Inherent Node 1 from Node
    • MeshInstance
      • Area
        • CollisionShape
  • Inherent Node 2 from Node [Duplicate of Inherent Node 1]
    • MeshInstance
      • Area
        • CollisionShape
  • Camera
  • Player
    • Kinematic Body
      • MeshInstance
      • CollisionShape

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 event bodyEntered will emits a signal on _on_Area_Body_entered to the player, which will remove the child from the root scene with get_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.

bug_remove_child

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.