Getting an 'invalid access'

Godot Version

4.6.2.stable

Question

I tried to update my game so the duplicated “animatedsprite2d” would become children of the grid_container. However, I would get an “_process: Invalid access to property or key ‘sprite_frames’ on a base object of type ‘previously freed’.” error and I’m not sure why. I would print the ‘placed_animated_sprites’ and they do show up in the output, so I know the array isn’t empty. The purpose of the _process() method is to animate rolling die, but by showing random die faces.

extends Node2D

var ghost_dice_bag
var placed_animated_sprites = []
var roll_balance: int
var total_balance: int

@onready var balance_amt_label: Label = $"../Main_CanvasLayer/VBoxContainer/HBoxContainer/Balance"
@onready var grid_container: GridContainer = $"../Main_CanvasLayer/VBoxContainer/GridContainer"
@onready var animated_sprite_2d: AnimatedSprite2D = $"../AnimatedSprite2D"
@onready var timer: Timer = $"../Timer"
var status: bool = false

@onready var upgrade_canvas_layer: CanvasLayer = $"../Upgrade_CanvasLayer"
@onready var upgrades: Control = $"../Upgrade_CanvasLayer/Upgrades"

# Called when the node enters the scene tree for the first time.
func _ready():
	places_dice()
	
func places_dice():
	ghost_dice_bag = Globals.dice_bag.duplicate()
	
	#Resets the array, so a new set of dice can be placed on the grid
	placed_animated_sprites.clear()
	
	if grid_container.get_child_count() != 0:
		grid_container.queue_free()
	
	for i in range(0, Globals.dice_bag.size()):
		#if statement runs only if the dice bag is not empty
		if ghost_dice_bag.is_empty() == false:
			var die_key = ghost_dice_bag.pick_random()
			var die_node = animated_sprite_2d.duplicate()
			die_node.animation = die_key
			die_node.visible = true
			
			#Needed for rolling mechanic
			placed_animated_sprites.append(die_node)
			
			#Nodes doesn't show
			grid_container.add_child(die_node)
			
			#Ensures the same die doesn't get choosen twice
			ghost_dice_bag.erase(die_key)
			
			#Places the die on a random frame
			var frame_count = die_node.sprite_frames.get_frame_count(die_key)
			die_node.frame = randi_range(0, frame_count)
	prints(placed_animated_sprites)

func _on_roll_dice_pressed():
	upgrade_canvas_layer.visible = false
	
	#Clears the dice from the screen. Without this, the dice sprite would be placed over each other
	for child in get_children():
		child.queue_free()
		
	#Places new dice
	places_dice()
	
	#Starts the dice 'rolling' animation
	status = true
	timer.start()

func _process(_delta: float):
	if status == true:
		for key in placed_animated_sprites:
			#for die in Globals.dice_bag:
				#Places the die on a random frame
			var frame_count = key.sprite_frames.get_frame_count(key) #<---doesn't work
			key.frame = randi_range(0, frame_count)

A screenshot of how I have the animation set up:

This error doesn’t tell you that the array is empty, it tells you the element you retrieved from the array has just been freed recently, so you can’t access it anymore. When you queue_free() the element that you know is in some array, it’s best to remove it from that array to prevent exactly this issue that you have.

Understood. What code alternative do you recommend then? I removed all of the ‘queue_free()” methods and I would get the following error:

E 0:00:01:690 dice_grid.gd:80 @ _process(): Animation ‘@AnimatedSprite2D@3:<AnimatedSprite2D#32950453843>’ doesn’t exist.
<C++ Error> Condition “!E” is true. Returning: 0
<C++ Source> scene/resources/sprite_frames.cpp:71 @ get_frame_count()
dice_grid.gd:80 @ _process()

Why would you do that?

what would you suggest then? What alternate code should I type to fix the issue at hand?

I suggested the solution in my previous post:

I took another look at my code and realized it was doing other things I didn’t intend. So I’m going to have to do some more rework than I thought, but I appreciate your feedback nevertheless.

1 Like