• Godot HelpProgramming
  • How do I free (or queue_free) a recently instanced scene? & how do I path to it for other purposes?

So let's say I am instancing a scene.

First I do this.

onready var Robot = load("res://Robot.tscn")

Then we do step 2:

func _on_Button_pressed():
        var b = Robot.instance()
        var p = position
        b.position = p
        get_node("..").add_child(b)

This all works fine and is making the instanced scene Robot.tscn appear on the object this script is attached to (an Area2D, if that matters). Now I want to delete that instanced scene elsewhere in this same script when pressing another button. How do I delete that instanced scene now, from within the scene it was brought into? This does not work: get_node("../b").queue_free() Nor does this: b.get_node("..").queue_free() And this doesn't work either: b.queue_free() Robot.queue_free() also doesn't seem to work, and free() on its own also doesn't work in any of the above.

How do I delete an instanced scene from the scene that I generated it into? And how do I path to the instanced scene otherwise for other purposes?

I cannot say for sure, but I have a few suggestions/thoughts:

| If I remember correctly, .. gets whatever is above it. So get_node(“../b”) is equivalent to get_parent().get_node(“b”). Is b the name of the Area2D? If it is, then I’d just use self.add_child(b).

| If what I wrote above is true, then the reason none of the snippets you are providing are working is because the node isn’t actually attached to the node this script is attached to, but rather the parent node that the script is attached to. Using self.add_child(b) will parent b to the node this script is attached to (you can remove self if you want, and just use add_child(b) instead)

| Another thing, the name of the newly instanced node will have some generated name, something like <insert node name here>@1 or something like that. If you want to use something like get_node(“b”), then you need to rename the node to b. You can do this in _on_Button_pressed by adding b.name = “b”

| Finally, and you may already know this, but you cannot use b.queue_free unless b is stored outside of your _on_Button_pressed function. If it is already stored outside of the _on_Button_pressed function, then you need to remove var from var b = Robot.instance(). If you want to access it again, then I’d highly suggest storing b in a variable outside of your functions, so you can access it at any time, from any function.

I’m not sure if anything I wrote will work. Currently I’m away from my development machine, so I cannot test any code.

If you link your project (or an example project showing the same issue), then I’ll take a look later and see if I can solve the problem (if you want).

var b is a function variable. It dies once it leaves scope. You cannot use it outside of your function. "b" is not the name of your node, it is the name of your variable.

@Somnivore said: var b is a function variable. It dies once it leaves scope. You cannot use it outside of your function. "b" is not the name of your node, it is the name of your variable.

What is the name of the node that has been brought into the scene? The name for the instance of Robot.tscn ? How do I reference that instanced scene?

@TwistedTwigleg said: I cannot say for sure, but I have a few suggestions/thoughts:

Thank you for the very thorough reply. I think I may have miscommunicated a bit, so let me be a tad more verbose. Quick background: The idea is we have like a workbench, and it can swap between different kinds of robots, who are saved as scenes with a Rigid2D body. You click one of three buttons to create a robot of that type (of a designated scene), then delete the old robot's scene. (I managed to create a workaround by defining a quick true/false switch in an auto loaded script, then putting a check for it being set to "true" into the integrate forces of the script attached to the instanced scene that triggered a queue_free() , but that is a really roundabout way to do something that I'm certain can be done somehow else, and I still want to be able to reference and path to the new instance!)

| If I remember correctly, .. gets whatever is above it. So get_node(“../b”) is equivalent to get_parent().get_node(“b”). Is b the name of the Area2D? If it is, then I’d just use self.add_child(b). b is just the random variable that I chose for this, not the name of the Area2D. The Area2D is named Area2D and the child of the root of the scene.

| If what I wrote above is true, then the reason none of the snippets you are providing are working is because the node isn’t actually attached to the node this script is attached to, but rather the parent node that the script is attached to. Using self.add_child(b) will parent b to the node this script is attached to (you can remove self if you want, and just use add_child(b) instead) Yes, it is attached to the parent node that this script is attached to. Shouldn't I still be able to reference it by doing ".." first, going up one level (to the root node of the scene) then back to the new instance?

| Another thing, the name of the newly instanced node will have some generated name, something like <insert node name here>@1 or something like that. If you want to use something like get_node(“b”), then you need to rename the node to b. You can do this in _on_Button_pressed by adding b.name = “b” What is that name? How is that name designated? The name of the node wasn't it. Is it Robot.instance()? Trying to rename it with b.name = "b" returns an error saying that that class does not exist for a RigidBody2D (which the instanced node is).

| Finally, and you may already know this, but you cannot use b.queue_free unless b is stored outside of your _on_Button_pressed function. If it is already stored outside of the _on_Button_pressed function, then you need to remove var from var b = Robot.instance(). If you want to access it again, then I’d highly suggest storing b in a variable outside of your functions, so you can access it at any time, from any function. This may be my oversight. Does this mean that if I define var b = Robot.instance() it will refer to the instance that has been brought in? Should that be done in an autoload/as a singleton if I want to access it from everywhere? If I place onready var Robot = load("res://Robot.tscn") and var b = Robot.instance() into an auto load script named, say, Save.gd, should I be able to reference an instance created of Robot.tscn using Save.b? (I suppose this is the next thing I try as I have time to dev tonight.)

@Zadck The root node of Robot.tscn has a name. When it's instantiated, the instance shares the same qualities of the PackedScene, including the names of its nodes in its hierarchy. The name you're looking for is the root node's name, which is the same node referenced by var b, as it is the instance generated from Robot.instance(). The exception is that several instantiated nodes who share the same parent and name will get their names auto-generated such as Node1, Node2, Node3 etc., so best practice is to keep the instance reference with your script as a member variable, thereby cutting out the get_node() middleman.

extends Node

var robot_instance = null #member variable, can be an array instead if you need many robot references stored

#elsewhere...
robot_instance = Robot.instance()

#elsewhere...
robot_instance.queue_free()
#using get_node() instead, albeit not recommended in this situation
get_node(str("../", robot_instance.name).queue_free()
5 years later