Removing Array elements properly

Godot Version

v4.4.1

Question

Can someone help explain to me how deleting elements from arrays is done properly.

I’ve got this very simple setup with 10 labels in an array, and a button which manually deletes the 5th element, however, it’s deleting the 7th element for some reason, this happens every time repeatedly.

Swapping around labels.remove_at(5) and labels[5].queue_free() removes the 6th element in the array (or Label 5).

So either way, still not the intended removal of element 5 (Label 4)
Screenshot here:

Here’s my code:

extends Control

# Nodes
@onready var array_size_label: Label = $ArraySizeLabel
@onready var delete_element_button: Button = $DeleteElementButton
@onready var labels_container: Control = $Labels

# Variables
var labels: Array[Label]

# Ready function
func _ready() -> void:
	# Add labels
	for loop: int in 10:
		var new_label: Label = Label.new()
		new_label.position.y = loop * 30
		new_label.text = str("Label: ", loop)
		labels_container.add_child(new_label)
		labels.append(new_label)

	# Delete Button
	delete_element_button.pressed.connect(func() -> void:
		labels.remove_at(5)
		labels[5].queue_free()
		print(str("Deleted item: ", labels[5]))
	)

# Process function
func _process(delta: float) -> void:
	array_size_label.text = str("Array Size: ", labels.size())

This removes the label at index 5 from the labels array. Then queue free’s the labelthat is now at index 5.

remove_at() removes the element then moves all the following elements down 1 to fill the hole.

2 Likes

Yes, that means your array of labels no longer knows about the 6th label, and every label shifts down one. Now when you remove the 6th label (index 5), it’s actually the 7th label.

By the way, removing index 5 would hit label 5, not 4.

1 Like

Oohh I see, because the remove_at() function starts at 0. I got confused thinking remove_at(1) would remove the first element Label 0. But remove_at(0) removes the first element Label 0, then remove_at(1) would be Label 1 etc etc.

And yeah, I realized using labels[5].queue_free() first made more sense.

Thanks guys, stupid question I know, but thank you regardless haha.

1 Like