Dictionary Values across nodes are shared. How to fix?

Godot Version



I am making a game that consists of a number of Point Nodes.

extends Node2D
class_name Point

@export var industry:Industry
@export var items:Dictionary
var pops:float

Each Point has an items Dictionary where the key is an Item, and the value is a float representing how much of that item is at that Point.

In the editor, in point.tscn it set the Items dictionary to be
key: Resource(“res://Assets/Items/Food.tres”)
value: 0

Also each Point has an Industry

extends Resource
class_name Industry

@export var industry_name:String
@export var output_per_pop:Dictionary

The Industry Farming.tres has the output_per_pop set to
" key: Resource(“res://Assets/Items/Food.tres”)
value: 2 "
in the editor

The desired behavior of the program is to update each Point with increased items. Each Point should have its own unique amount of food stored in the items Dictionary.
However, my problem is that this is not happening! Instead updating the Items[Food] value of one Point updates the Items[Food] value of every Point!

The _process() of Point looks like this

func _process(delta):
	for item in industry.output_per_pop:
		var new_items:float = delta * industry.output_per_pop[item] * pops
		items[item] += new_items

When I put a breakpoint on “pass” I can see that across all my Point Nodes the key of “items” is an Object with the same Object id. Also the value is the same for all of them. Increasing the Items[Food] value of one Point Node changes the value for all point nodes.
It seems like the “items” dictionary of all Point Nodes all point to the same location in memory?
Why does this happen even though other variables like “pops” are unique between Point Nodes?
How do I make it so that the value of each items[Food] is different across my different point nodes?

Dictionaries are referenced, you will have to call items.duplicate() at some point in your script. Maybe a export for starting values, then on ready duplicate

@export var starting_items: Dictionary
var items: Dictionary

func _ready() -> void:
    items = starting_items.duplicate()

As for why is a implicit optimization. Base types (float, int, bool) are copied, I believe some extra types like vectors are also copied. Others are referenced, so changing one will change all other references. I believe the only real way to tell is if the type has a duplicate function it’s referenced.

This is much faster as container-types are potentially very expensive to copy, and usually you’ll want to reference something like a player instead of copying one. Languages like C++ have everything copy by default and require pointers to reference.

Thank you, this fixed the issue!

I think the thing that confused me is that usually if you have separate Nodes with pass-by-reference variables each Node has its own memory location for each pass-by-reference variable.
I guess that this is not necessarily true when you set it up like I did through the editor. Perhaps because each Point Node is an instance of my default Point Node Scene? So therefore they were all getting the value (a reference) from the same source?

Yes I believe the combination of @export and instancing exacerbated the effect.