How to change one instance without them all changing

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

It seems like this should be simple, but I haven’t figured it out yet.

I’d like to programmatically load many instances of this scene:

extends Node2D

var Stats = preload("res://creatures/components/Stats.tscn")
var Stats_sheep = preload("res://creatures/components/Stats_sheep.tscn")

export var stats = {}

func init_stats(name):
	# type of creature
	match name:
		"sheep":
			stats = Stats_sheep.duplicate(true).instance()
		_:
			stats = Stats.duplicate(true).instance()
	stats = stats.get_stats()
	# sprite
	set_sprite()
	# sight
	set_sight()


func set_sprite():
	var sprite = Sprite.new().duplicate()
	add_child(sprite)
	sprite.set_texture(stats["sprite"])


func set_sight():
	var sight = Area2D.new().duplicate()
	add_child(sight)
	var sight_area = CollisionShape2D.new().duplicate()
	sight.add_child(sight_area)
	sight_area.set_shape(CircleShape2D.new().duplicate())
	sight_area.shape.set_radius(stats["sight_radius"])

And this is the structure of the Stats scenes:

extends Node

export var stats = {
	# type of creature
	"type": "sheep",
	# sprite resource
	"sprite": preload("res://creatures/sprites/sheep.png"),
	# sight
	"sight_radius": 20
}

func get_stats():
	return stats.duplicate()

When I instance these scenes, I want to be able to independently set the radius of the sight_area, but when I try to do that using this script, all of them come out the same size:

extends Node2D


var Creature = \
  preload("res://creatures/Creature.tscn")


func _ready():
	for i in range(4):
		var creature = Creature.instance().duplicate()
		creature.init_stats("sheep")
		if i == 3:
			creature.stats["sight_radius"] = 5
		add_child(creature)
		creature.position.x = randf()*80
		creature.position.y = randf()*80
	
	for _i in range(3):
		var creature = Creature.instance().duplicate()
		creature.init_stats("")
		add_child(creature)
		creature.position.x = randf()*80
		creature.position.y = randf()*80

As you see in the code, I’m trying to make duplicates of the resources rather than maintaining references to the same resource, but even then, why can’t I even directly change creature.stats independently when I make a duplicate instance.

I have also enabled “Local To Scene” for every resource I’m using in the editor.

I’m sure there’s a simple way to do this, but I could really use some help here!

Thank you in advance!

:bust_in_silhouette: Reply From: Ghostrix98

I believe the issue is in the following lines:

creature.init_stats("sheep")
if i == 3:
    creature.stats["sight_radius"] = 5

In your Creature.init_stats() you called your set_sight() function which created and set the collision shape. The issue is that when you set the sight radius to 5 in the 3rd line the collision shape is not updated.

You should be able to update it if you add creature.set_sight() after the 3rd line inside the if statement.

Side note: You can safely remove all the .duplicate()s after the .new() calls as the .new() function already returns a unique copy. The Overall effect is the same without them.

Thank you so much! It seems so obvious now. I will accept this answer when I try this out later today.

t8 | 2021-11-14 21:22