Object refusing to queue_free and instance duplication

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By lemone

Heya I was making a thing where you can click a mushroom rigid body and it replaces itself with a kinematic body that follows your cursor and when you click again it becomes a rigid body again. The pick action is just the left mouse button. The kinematic shroom consists of a couple of areas a collision shape and a sprite. The rigid mushroom consists of an area a collision shape and a sprite. They are both children of a Control node

Everything else runs fine, but when I click the mushroom it can randomly duplicate and abort the queue_free() command so i click on a kinematic body to drop it but it remains and spawns in a rigid body. Also when I click at the dropped rigid body it spawns in 2 kinematic bodies. Its very inconsistent though as I have gotten a successfull grab and drop multiple times

Can someone help me sort out this problem?

Here’s a script of the following mushroom

extends KinematicBody2D

var picked = false
var speed = 600
var velocity = Vector2.ZERO
var rigid = load("res://Game files/UI Elements/MushroomRigid.tscn")

func _physics_process(delta):
var mouse = get_global_mouse_position() - self.position
mouse = mouse.normalized() * delta * speed
position += mouse
move_and_slide(mouse)

func _on_Area2D_mouse_entered():
speed = 0

func _on_Area2D_mouse_exited():
speed = 400

func _on_Area2D2_input_event(viewport, event, shape_idx):
if Input.is_action_just_pressed("pick"):
	var rig = rigid.instance()
	rig.position = self.position
	get_tree().get_root().add_child(rig)
	queue_free()

And this is the script of the rigidbody one

extends RigidBody2D

var movie = load("res://Game files/UI Elements/MushroomFollow.tscn")

func _on_Area2D_input_event(viewport, event, shape_idx):
if Input.is_action_just_pressed("pick"):
	var mov = movie.instance()
	mov.position = self.position
	get_tree().get_root().add_child(mov)
	queue_free()
func _on_Area2D2_input_event(viewport, event, shape_idx):
    if Input.is_action_just_pressed("pick"):
        # do stuff

I think that these conditions are essentially the problem because they’re always actioning a ‘pick’ action, which can happen multiple times. Introduce a condition variable to indicate that the object state has changed; e.g.

var actioned: bool = false

func _on_Area2D2_input_event(viewport, event, shape_idx):
    if not actioned and Input.is_action_just_pressed("pick"):
        # do stuff
        actioned = true

Likewise if queue_free has been triggered, that’s also a testable condition. That might get you started anyway, good luck.

spaceyjase | 2023-05-09 16:21

o yep that fixed it thanks!!

lemone | 2023-05-09 16:54

:bust_in_silhouette: Reply From: jgee_23_

Hi! I’m not sure if adding a child directly to root has to do with this, but it sure is bad practice. You can change the main scene via change_scene() or change_scene_to().

If what you’re aiming for is to make a single item change (not the whole scene), then you can replace:

get_tree().get_root().get_node("World").add_child(rig)
queue_free()

with

get_tree().get_root().get_node("World").add_child(rig)
rig.connect("tree_entered", self, "exit")

and have a new function exit():

func exit():
    queue_free()

this will ensure that the object will be removed once the new object has entered the tree, since (if I remember correctly) an object cannot be removed while it’s adding another.