Array erase() not erasing

Godot Version

4.6 stable Windows 11

Question

So I have this code:

print("existing loot before deletion:", existing_loot)
	var previous_list : Array[Area2D] = existing_loot
	for interactable : Area2D in previous_list :
		print("checking interactable")
		if interactable == null :
			print("interactable is null")
			existing_loot.erase(interactable)
			print("interactable erased")
	print("existing loot after deletion:", existing_loot)
	for interactable : Area2D in existing_loot :
		interactable.wave_lifespan -= 1
		if interactable.wave_lifespan <= 0 :
			interactable.queue_free()

What this is supposed to do is create a temporary array equivalent to an existing_loot array, and iterate through it to remove all the freed objects from the existing_loot array. But when I iterate through the existing_loot array to modify a variable of each item in it, I get an error that the variable doesn’t exist because the object is freed. This is consistent with the print() line right after the object-removal loop, which returns the exact same array as the very first print() line, indicating that nothing has changed about existing_loot at all, and the erase() function in the first loop has not erased the objects from existing_loot as intended.

I imagine this has something to do with the engine not recognising the freed objects in the temporary array as the same freed objects in the existing array, but I don’t know for sure. How can I fix this? How can I remove every freed object from existing_loot? Any help is appreciated.

Arrays are assigned by reference, not by value. If you want a (shallow) copy, you need to use duplicate()

var previous_list : Array[Area2D] = existing_loot.duplicate()

Tried this and nothing has changed. Same error, arrays print the same.

what @normalized suggested should work. So you are probably doing something else that you didn’t mention.

Where exactly do you get the error?

The error is Invalid access to property or key 'wave_lifespan' on a base object of type 'previously freed'. and it’s on the line interactable.wave_lifespan -= 1.

This has nothing to with arrays directly. Arrays only store references to objects. Reference validity doesn’t depend on its storage in an array.

I don’t know what that means, and that doesn’t tell me how to fix it.

Don’t access the object if the instance is not valid.

That’s why I tried to remove null instances from the array, but it didn’t work.

Don’t remove stuff from the array while you iterate over it. Use Array::filter() instead.

array = array.filter(
	func(element): 
		return is_instance_valid(element)
)

Now I’m trying this out:

print("existing loot before deletion:", existing_loot)
	existing_loot = existing_loot.filter(func(object : Area2D) -> bool: return is_instance_valid(object))
	print("existing loot after deletion:", existing_loot)
	for interactable : Area2D in existing_loot :
		interactable.wave_lifespan -= 1
		if interactable.wave_lifespan <= 0 :
			interactable.queue_free()

But my print function immediately after the filter() function returns a completely empty array, which isn’t supposed to happen as not all objects in the array were freed.

Don’t declare the type of lambda’s argument, or declare it as Variant

When a Godot object is used as an argument, a copy of the object itself is not passed to the function. Instead, a pointer to the object is used.

Let’s say your object is a guy named Bob. When you use Bob is a method call you are not working on Bob directly - instead you are calling Bob on the phone and saying “Hey, do this”.

This can lead to some strange behavior if you aren’t careful. The behavior you’re seeing is because Bob died, and Godot is saying “I don’t know what to do. Bob is dead and I’m not a psychic.”

So you say, fine - Godot before you tell Bob to do something make sure he is alive. If not, do something else.