Variable acts as a reference instead of only storing the current value when setting it

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

I have a script attached to a node that shows a sprite to indicate when the player’s inventory has changed. The inventory is an array in a global singleton called Global. This is the (stripped down) code I am using:

extends Node2D
var inventory = []

func _ready():
	inventory = Global.inventory
	modulate.a = 0

func _process(delta):
	if not inventory == Global.inventory:
		inventory = Global.inventory
		modulate.a = 1

		# Then I wait for a second before setting modulate.a back to 0

However, the if statement is never triggered (the object never has its modulate.a set to 1), even when Global.inventory changes (and should therefore differ from the local variable inventory). After debugging, I found that inventory is always set to Global.inventory, even though it should only be updated in the if statement. It looks like inventory doesn’t just store the value of Global.inventory at the time of setting it but has become a reference to the actual property.

How do I set the local variable to the value of Global.inventory without it always updating its value?

I don’t fully understand what you’re trying to do here, but I have a few comments:

First, this code will simply point both variables to the same internal array object:

inventory = Global.inventory

You can create a copy of an array via the duplicate() method. So…

inventory = Global.inventory.duplicate()

Maybe that’s what you’re after?

This code looks suspect (and likely not what you intend?):

if not inventory == Global.inventory:

That will resolve to either False == Global.inventory or True == Global.inventory depending on the contents of inventory, which probably isn’t what you intended…

Were you maybe trying for this? Though, again, these will always be equal currently since both variables point to the same array object.

if inventory != Global.inventory:

jgodfrey | 2022-11-23 03:52

This is completely normal.

func _ready():
    inventory = Global.inventory

Arrays in godot are passed by reference, so after this executes, both inventory and Global.inventory point to the same array in memory.

To avoid this you can use the following code:

func _ready():
    inventory = [] + Global.inventory

This will create a new array and store it in inventory.

Now for the other part of your code:

func _process(delta):
    if not inventory == Global.inventory:
        inventory = Global.inventory
        modulate.a = 1

What exactly are you trying to achieve here?

Juxxec | 2022-11-23 08:00

Thank you for your great answer! duplicate() (or inventory = [] + Global.inventory) did indeed solve my problem.

Regarding your second point, on paper I understand why my logic in the if should evaluate the way you described it but for some reason it still works perfectly as if it was resolved to if not (inventory == Global.inventory). According to GDScript reference — Godot Engine (latest) documentation in English, the == operator has a higher priority than not so that part seems to be fine. I’ll still change it to != since that makes the code easier to understand.

Cucumber | 2022-11-23 16:11

Yeah, looking at the operator precedence docs, I think you’re right (apologies for the noise)… But, I do think the != is much more standard in this case and definitely easier to understand the intent.

Anyway, glad you got things working. :slight_smile:

jgodfrey | 2022-11-23 16:57

Thanks again for your help! :slight_smile:

Cucumber | 2022-11-24 02:49