How to remove one instantiated scene instead of all?

Godot Version

4.7

Question

Hi!!!

In my game, I have a spawner (handled with the code below) thats working fine. Everything is, actually, except when I have more than one person who ordered water, and try to remove it.

	if water_ordered:
		var person_spawn_w = water_person.instantiate()
		add_child(person_spawn_w)

I tried to add a variable that despawns the person whenever they get their order:

#in the water_person code, the above code is in the main node of the order screen.

if Globals.waterGone:
    water_person.visible = false

I was hoping, on the one percent chance, that that would actually work lol. But i cant seem to find anything that would actually work, ive been at it for a half hour. Any thoughts on how to remove just the customer you gave the item to, rather than every customer of that type?

Well if it’s a Global property then it’s going to affect everything using that same Global. You will need a variable inside the attached script.

I don’t fully understand your problem, and I don’t have all the code, so I’d guess where ever you set Globals.waterGone should instead emit a signal, call a function, or assign a class variable instead of the global.

For example the statement “you gave the item to” implies that there is a function that understands which customer you are giving something to, so you could delete that customer, or assign a variable on that customer, at that point in code.

You cannot hide a scene that’s not instantiated. You can hide the instance.

If you need to remove the last person_spawn_w you added to tree you should get the nodepath and perform a queue _free() on it

E.g.

get_node(“node path of water person”).queue_free()

A few things:

1: The main misunderstanding here, as others have mentioned above, is you’re confusing the scene with the instance of the scene.

water_person is your scene (PackedScene). When you do:

		var person_spawn_w = water_person.instantiate()
		add_child(person_spawn_w)

person_spawn_w is an instance of the scene. You correctly add the instance as a child of the current scene.

So when you want to reference the instance in the future, you have to call it specifically, not the water_person scene it was instantiated from. I.e. you need to call the person_spawn_w object.

But how? The var reference to person_spawn_w is lost from scope after your if statement. So you need another way to call it.

There are a few ways you can do this, I’ll show you one using “groups”:

If you add your water people to a group, you can loop through them later:

    if water_ordered:
        var person_spawn_w = water_person.instantiate()
        add_child(person_spawn_w)
        person_spawn_w.add_to_group("water_people")

Then later you can loop through them:

for water_person in get_tree().get_nodes_in_group("water_people"):
    ...<do something with water_person>...

2: To get rid of a node you don’t change .visible (that’s just visibility), you should use queue_free().

E.g.

for water_person in get_tree().get_nodes_in_group("water_people"):
    water_person.queue_free()

The above will clear all instanced nodes in the water_people group.

3: It’s unclear in your question what you mean by “despawn a person whenever they get their order”. You’ve only shown that you are instancing water_people, but you don’t show us how you are recording that they were given water. You would have to set some kind of tracking property on the water_people to do that. Then (let’s say your tracking prop is called “received_water”), you could do something like:

for water_person in get_tree().get_nodes_in_group("water_people"):
    if water_person.received_water:
        water_person.queue_free()

sorry i just realized i wasnt clear lol

The customer isnt a global property, but it is its own seperate scene, so i used globals to make it easier to transfer data between the person who wanted water and the main node. SO the water person is a seperate scene from the minigame.

This is where I record it:

	if Globals.water_entered:
		if Input.is_action_just_pressed("interact"):
			if Globals.water_had:
				if Input.is_action_just_pressed("interact"):
					main_node.total_served = main_node.total_served + 1
					print(main_node.total_served)
					Globals.water_had = false

water_entered being the customer area where you can give the order, water had being if you have water in your hand, and total_served being the tally.

anyways, i tried this!

					for water_person in get_tree().get_nodes_in_group("water_people"):
						water_person.queue_free()

It doesnt work, though, I added a global group to the water person, what did i do wrong?

But that makes the data global, instead of person-specific. I can’t imagine water_entered being useful as a global either, maybe sharing more about your project’s scene structure would help.

Do you use collision to interact with these customers? Maybe you can get a reference to them at that point, for example the body_entered signal will emit the other overlapping node as body, so you have both parts of the equation.

I will try that again! The reason i made it global in the first place, though, is because everytime i tried to connect the area without a global variable being turned true when you entered the area of the customer (i use area_entered because my player has an area attached), the script would for some reason disconnect the area trigger in the code. Nothing would work when i did that, but then again that was area_entered, so ill try it with body_entered!

if you are trying to detect areas overlapping then you should use area_entered, the other body_entered signal will only detect bodies entering the area, if your player is a CharacterBody or RigidBody then body entered will work fine.

It could be that you haven’t added the group to the water person properly. If you add a print statement in that for loop (e.g. before water_person.queue_free()) does it print out anything?

If it does, then it’s working and the water_person instances should be cleared.

If it doesn’t then it means you have not added the group and so it’s not looping over anything. Make sure you added the root node of the water_person scene to the group, not a child of it.

Edit: Also, try renaming the loop variable, since water_person is also the name of your scene var and it may be clashing depending on where you’re calling this in your code:

for wp_instance in get_tree().get_nodes_in_group("water_people"):
    wp_instance.queue_free()