Can't instantiate Resource

Godot Version

4.2

Question

How do I create an instance of a Resource?
I have tried several things and asked google and duckduckgo, along with watching videos on youtube, and I just can’t find a solution.

I made a Resource named Components

Components.gd

extends Resource

@export var name : String
@export var quantity : int
@export var texture : Texture

@export var volume : float
@export var weight : float

then I created a new Resource file named Cord which uses Components.gd as its script.

Now in a _ready() function I’m trying to give the player some starting items, but I want to dynamically change the item quantity, so in my noob mindset, I will just instantiate it and at each location this item exists, it can have a different quantity and the player through logic can choose how much of each item he wants to pick up, which means I just have to update the quantity value on two instances.

Note that this is just prototyping. Also the print statements are just for debugging.

func _ready():
	# Initial Inventory
	var cord_item = load("res://res/components/Cord.tres")
	print(cord_item )
	var new_item = cord_item .new()
	print(new_item )

So the first print correctly outputs a Resource ID, but then when I instantiate it, this error comes up:

Invalid call. Nonexistent function ‘new’ in base ‘Resource (Components.gd)’.

I don’t understand what I’m doing wrong as everywhere I’ve seen anyone instantiating a resource this is what they do.

Help appreciated.

var new_item = cord_item.new()

You don’t need this “.new()” because when you loaded the Resource, you already created the Resource (if you look load documentation, you’ll see this function return a Resource), this “.new()” is when you create the Resource from zero, like this

func _ready():
	# Lets suppose we have a Sprite2D node and we want to 
	# put a material in this node
	# We didn't loaded from anywhere, in this case we use .new()
	var new_material := CanvasItemMaterial.new()
	get_node("Sprite2D").material = new_material

1 Like

For your script you can preload the Components.gd file and call .new() on that.

If you want to use the Cord.tres defined resource you can call .duplicate() on it to make alterable copy.

1 Like

Unfortunately that doesn’t solve the problem, because the whole point is that I create different instances of that resource, so that I can modify them independently.

For example, I want the cord resource in the player inventory to have a quantity variable set at 10, while I want a chest somewhere on the map to have the same cord resource but with a quantity of 40.

If I don’t instantiate them, they just use the same resource data, any change done to any variable that holds that Resource, is a change commited to all variables.

I understand that I can just script it in a way that an independent variable holds the quantity, but I wanted to improve this feature on more levels, like item quality, item condition, and so on, and I find it much more practical if I could instantiate and hold all the data for the item in the item instantiated resource.

Thanks, that seems to be the solution, duplicate() works as I intended.

Now another issue arose, I created an _init(): function on my resource, so that I can pass a parameter to the new instance of the item, in this case I want to pass a quantity variable, however it doesn’t work, here is my code:

In my resource script, Components.gd

extends Resource

@export var name : String
@export var quantity : int
@export var texture : Texture

@export var volume : float
@export var weight : float


func _init(_quantity = 1):
	quantity = _quantity

And here where I’m instanciating the new resources:

inventory_array = [load("res://res/components/Cord.tres").duplicate(10),
						load("res://res/components/Cord.tres").duplicate(40)]
print(inventory_array[0].quantity , " ", inventory_array[1].quantity)

It prints 0 , 0.
Any solution to this?

Update:
I’ve meddled with some things, it seems that if I remove the @export from the variable I’m trying to pass a parameter to, in this case, quantity, now the duplicated resource gets the default value I assigned on initialization, in this case, 1.

duplicate does not take parameters passed to _init, it’s valid code because you are submitting flags to duplicate() that you likely don’t intend to. You will have to duplicate, then change your variable, then submit to the array.

Using preload and/or storing the resource in a variable is good practice, should perform much faster.

const cord_tres = preload("res://res/components/Cord.tres")

func add_cord(arr: Array, quantity: int) -> void:
    var clone = cord_tres.duplicate()
    clone.quantity = quantity
    arr.append(clone)
1 Like