Copying Array data around different classes problem

Godot Version

v4.4.1 stable

Question

Can someone give me a hand with figuring this problem out please?

I’m trying to pass some data around a few classes, but the Array data is getting turned into Freed Objects (I have no idea what that is). Here is my code:

class_name EndScreenData extends Object

# Variables
var all_champions: Array[Champion]

This is in a global autoload, this is what I’m attempting using as an intermediary class to store the Array.

class_name BattleController extends Node2D

# Variables
var current_round: int = 1
var all_champions: Array[Champion]

# Change battle state
func change_battle_state(new_battle_state: BATTLE_STATE) -> void:
	# Post-state change, going into this state
	match battle_state:
		BATTLE_STATE.PREBATTLE:
			pass
		BATTLE_STATE.BATTLING:
			turn_timer.start()
		BATTLE_STATE.ENDING:
			turn_timer.stop()
			end_battle()
			Utils.end_screen_data.all_champions = all_champions.duplicate()

Here is the main class with the Array data (I am appending to the Array in several places, all of this data is fine). Note, I’m using .duplicate() on the Array to try and get the data to stick (to no avail) - but I’ve tried using .duplicate and not.

class_name BattleOverScreen extends Control

# Variables
var all_champions: Array[Champion]

# Ready function
func _ready() -> void:
	# Load All Champion data from Utils
	all_champions = Utils.end_screen_data.all_champions

And finally the class I want the data to be copied too. When I print out the Array in this class, it displays this in the console:

So the Battle Controller script (and associated Scene) are being queue_freed, but only after I’m trying to copy over the data. I’m confused because it is suppose to have 12 objects (Champions in my game) so it got that bit right.

I’m sure it’s simple and I’m being an idiot, but can someone help me fix this?

Have you tried using deep duplicate?

var copied_champions = All_Champions.duplicate(true)

What if the champions are not loaded? And it’s an empty array.

Yes, while still trying to figure it out, I have tried using deep copy a.k.a .duplicate(true).

And yes the initial Array in the Battle Controller is populated properly, here’s a screen shot of that print out:

This is the outcome I expected to have after duplicating the Array, but sadly I still cant figure it out.

Thank you for trying though, I appreciate it! But I’m still looking for an answer.

You mean it doesn’t work as expected?

Yes, it doesn’t work as I expected.

So that screen shot above is the all_champions Array in the Battle Controller, and I can access the elements all fine, when I duplicated them to the Utils.end_screen_data.all_champions, I expected to see the same result, but it just shows the first console print out I posted, all the elements are Freed Object for some reason.

I tried Googling a Freed Object and still don’t get what it even is, I thought an element could be either null or have a value, didn’t even know there was a third option lol.

So I’m still trying to get the data from all_champions Array in the Battle Controller to Utils.end_screen_data.all_champions and over to BattleOverScreen all_champions.

A freed obj is a thing that godot deleted from memory to optimize and save memory.

Oohh okay, I would have just thought that was a null value.

It’s I think like a null, but godot knows it used to be something but godot has already delated it

Right, seems a little unnecessary but anywho.

Here’s a crude paint drawing of a psudo code I’m trying to achieve, if this helps.

The array just stores a ref node path/value of the obj…soo it means your champions are just getting deleted, now we have to find a way not to delate them

The reason deep duplicate is working and the shallow duplicate isnt, is because the shallow duplicate is only storing object REFERENCES (which are pointing to the memory where its stored), whether the deep copy creates NEW objects (champions) and NEW References. So before you log your array of champions, you probably delete or reset them somewhere, deleting the actual objects. But your shallow copy is still referencing now objects, which were deleted, hence “Freed Objects”

Here is a doc link on how objects and primitives values are copied, this in javascript but i am pretty sure godot does it kind of the same:

Sorry, to be clear, deep duplicate, did NOT work. I’ve set it both times.

Well the Array is deleted automatically when I change scenes, because they are 2 separate Scenes. Hence the reason for wanting to copy the data in the first place (rather then just use the initial all_champions in the Battle Controller class).

If you know of a better way to take data from one Scene to another, that would be cool too. But I wouldn’t know how to do that.

I am sorry, but I am not understanding, why the deep copy was not the solution, the screenshot you posted above, was the correct array you needed no?

That was showing the data in the Battle Controller class (the class I am trying to copy from).

Not the Utils and BattleOverScreen classes (where I’m trying to copy the data too).

I was just showing the original Array has stored elements in it (bottom left circle in the psudo code paint drawing).

Ah now I understand thanks!

image

Could you show us what the end_battle() function does? If the deep copy isnt even working, it is maybe deleted beforehand (before it is saved to the global class)

You have to copy your champions to a global scene then.

What your champion nodes have? Like any name,scores,rank etc?

# End battle
func end_battle() -> void:
	battle_ui.outcome_label.visible = true
	battle_ui.continue_button.visible = true

	if player_team.get_child_count() >= 1:
		battle_ui.outcome_label.text = "Victory!"	
	else:
		battle_ui.outcome_label.text = "Defeat!"

The end_battle() function is just some UI stuff, nothing to do with the all_champions Array

The array stores the node value or whatever it’s called, if it doesn’t exist it just finds nothing and calls it a freed obj.

Soo I think deep duplicate is maybe just not working

1 Like