How to use get_instance_id to a new instance replace an old instance if they are in the same position?

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

The title pretty much says everything, I need an instance (that spawns at the position of a sprite which follows the mouse and snaps to a tile map’s tiles) to delete another instance if there is another one in the exact position. The instances aren’t stored in the tilemap at all, they are stored in a Node2D ( which is separate to the Main Node2D of the scene) with a Y-Sort in it. I have asked this before but I’m trying to take a different approach to it. My current idea is for the newly instanced object to detect if another instanced object is in the exact same position, and if there is another instanced object, the newly instanced object gets the old instance’s id and delete said old instance.
Possibly something like this? :

(In the Main scenes script which handles placing the buildings)

func place_building():
if BuildingValue.buildingToPlace == 0:
    var A = preload("path/A.tscn")
    var A_spawn = A.instance()
    A_spawn.position = $HighlightBox.position
    $Node2D.add_child(A_spawn)
    
if BuildingValue.buildingToPlace == 1:
    var B = preload("path/B.tscn")
    var B_spawn = B.instance()
    B_spawn.position = $HighlightBox.position
    $Node2D.add_child(B_spawn)

func _input(event):
	if Input.is_action_just_released("place") && GameManager.can_place == true:
		place_building()
	else:
        if ExampleNewInstance.position == ExampleOtherInstance.position:
            var ExampleVar = ExampleOtherInstance.get_instance_id()
            $Node2D.remove_child(ExampleOtherInstance)

The top function is just an example of the place_building() function.
I don’t know if this even remotely close, my guess is it’s not but I’m just sharing my thinking process.
Thanks in advance :smiley:

:bust_in_silhouette: Reply From: timothybrentwood

I don’t think the objects you’re placing should know how to interact with other objects you’ve placed (unless that’s a game mechanic). It would be better to let the parent node know how to manage that. Assuming buildings are sized uniformly, I would create a dictionary where the keys are the positions where building instances are currently located and the value being either the building object itself or the object’s instance id. Then placing would be something like this:

func place_building_at_position(building_position):
    var building_at_position = building_dictionary.get(building_position)

    if not building_at_position:
        pass # no building in the dictionary, nothing to clean up
    elif not is_instance_valid(building_at_position):
        return # can't be too careful when dealing with mouse stuff
    elif $Node2D.is_a_parent_of(building_at_position):
        # clean up old node if we found one
        $Node2D.remove_child(building_at_position) # or instance_from_id(building_at_position)
        building_at_position.queue_free()

    # just make place_building() return the object instanced or its id
    var new_building = place_building()
    building_dictionary[building_position] = new_building

Sorry didn’t see this till now!
After asking this question I ended up coming up with a rather convoluted solution, it works but probably isn’t the best way to do it, though it is pretty reliable, I haven’t had any problems so far. The solution I came up with was creating a timer inside the instances set to 0.08 seconds, and a variable inside the instances scripts called wait_for_timer.
This is how I did it:

var wait_for_timer = true

func _ready():
	$Timer.start()
	wait_for_timer = true #when wait_for_timer is true, this instance can not be deleted

func _on_Area2D_area_entered(area):
	if !wait_for_timer: #if wait_for_timer is false then delete self
		queue_free() #this will delete the object if the timer isn't running

func _on_Timer_timeout():
	$Timer.stop()
	wait_for_timer = false #when timer finished set wait_for_timer to false

Lazulily | 2021-12-01 22:40

Just set the Timer to autostart then:

func _on_Area2D_area_entered(area):
    if $Timer.is_stopped():
        queue_free()

timothybrentwood | 2021-12-02 00:45