Invalid call. Nonexistent function 'get_hframes' in base 'Nil'.

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

Hey folks,

Im trying to make a random item generator and want to use different art assets depending on the type of item is made. Each art asset is a grid with different sprites, so I want to first select the type of item, and then choose a random frame from that asset and use that for the sprite itself. Here is the code:

extends Area2D
var art_potions = preload("res://Assets/Art_Potion.tscn")
var art_medwep = preload("res://Assets/Art_MedWep.tscn")
onready var image = $Sprite

var possible_items = [
	art_potions,
	art_medwep
]


func _ready():
	randomize()
	roll_item_type()
	

func roll_item_type():
	possible_items.shuffle()
	print(possible_items[0])
	image = add_child(possible_items[0].instance())
	set_sprite()
	
func set_sprite():
	var image_h_number = image.get_hframes()
	var image_v_number = image.get_vframes()
	
	var hframe = randi() % image_h_number
	var vframe = randi() % image_v_number
	
	var randframe = Vector2(hframe, vframe)
	
	image.set_frame_coords(randframe)
	

the $Sprite is a sprite node bound to the item itself. it has the same art asset as art_potions. Changing the line from

onready var image = $Sprite

to

var image = null

gets me the same error.

The error is Invalid call. Nonexistent function ‘get_hframes’ in base ‘Nil’. The code works when the roll_item_type function is removed, so I guess the error comes from add_child, though I dont know how or why.

Any help would be appreciated.
Thanks

EDIT: The ‘art_potions’ and ‘art_medwep’ are bots scenes with only a Sprite node.

:bust_in_silhouette: Reply From: Myrmex

This line
image = add_child(possible_items[0].instance())
creates child node inside the object this script is attached to ($Area2D/Sprite) and then image variable becomes a reference to that node or something, try print(image) to know for sure.
So at the moment you call image.get_hframes(), the image variable is anything but Sprite.
Try to create an instance first and add it as child after it’s processed by set_sprite().

Well you found the issue, it prints Null. However, it does actually also set the sprite as it should. Any tips on how to find the correct node?

EDIT: Well I got it to work. I added this
var selected_item = possible_items[0].instance()
and replaced most references to image and now it works. Thanks for pointing me in the right direction.

Loxias | 2020-07-31 21:23

I got it to work, looks like this now:

func roll_item_type():
	possible_items.shuffle()
	var selected_item = possible_items[0].instance()
	image = add_child(selected_item)
	set_sprite(selected_item)

func set_sprite(selected_item):
	var image_h_number = selected_item.get_hframes()
	var image_v_number = selected_item.get_vframes()
	
	var hframe = randi() % image_h_number
	var vframe = randi() % image_v_number
	
	var randframe = Vector2(hframe, vframe)
	print(image_h_number, image_v_number, randframe)
	selected_item.set_frame_coords(randframe)

I just had to make the Array adress into its own variable and now everything works like I wanted it to. Thanks for pointing me in the right direction.

Loxias | 2020-07-31 22:05