Why am I getting an error saying the base is nil and function is non-existent ?

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

I added this function in my player script :

func heartDisplay():
	var heart = TextureRect.new()
	heart.texture = load("res://Textures/Heart.png")
	heartBox.add_child(heart)

here heartBox = get_parent().get_node("HeartBox")

When I call this function in the same script, it works fine.

Now the issue is that I wanted to call this function in another script. So in another script I made a variable var playerReference = load("res://Player/Player.gd").new() so that I can access the function in another script. But now I get an error saying that add_child is non existent.

This is the function from where am calling heartDisplay()

func _on_Health_area_entered(area: Area2D) -> void:
	if area.is_in_group("player"):
		$SpriteDisappearTimer.start()  # calling queue free here
		$HealthSound.stream = load("res://Sounds/PowerSound.wav")
		$HealthSound.play()
		global.armor+=1
		playerReference.heartDisplay()
:bust_in_silhouette: Reply From: Andrea

i think the hearthDisplay function requires the playerscene to be instanced an present in the three, but you only loaded the script.
maybe this is where the error come from?

I actually tried using another approach. I attached a script to VBoxContainer which I have named HeartBox and within that script I have transferred the function :

extends VBoxContainer

func heartDisplay():
	print('HeartBox')
	var heart = TextureRect.new()
	heart.texture = load("res://Textures/Heart.png")
	add_child(heart)

and now In the other script I am calling this function by using

var heartBoxReference = load("res://MainScenes/HeartBox.gd").new() 

This is how I call heartDisplay() :

heartBoxReference.heartDisplay()

The call is successful as HeartBox gets printed but it seems lie add_child(heart) is still not working ! I get no errors now and if I call heartDisplay() where I have declared it i.e in VBoxContainer Script, then it works. But then the heart texture gets added only in the beginning in _ready() function and several times in _process() function which is not strange given the nature of these functions. What’s strange is, why this function not adding texture when I call it from other script?

Scavex | 2021-01-05 15:53

i think your problem lies in the fact that loading a script into a resource variable, is not the same as adding new script to a node.
infact the hearthBoxReference will be threated as an orphan node, with no type.

When you call heartDisplay (from the “other” node), you are calling it on this orphan script node (NOT on the “other” node), therefore adding child and displaying texture on the orphan has no visible effect.

again, i suggest to instance and add the vbox container, and call the function from it

var box=load("res://MainScenes/HeartBox.tscn").instance()
add_child(box)
box.heartDisplay()

or just add the vbox container in the tree using the editor

Andrea | 2021-01-05 16:49

I am really confused! I have this function in my player script :

func heartRemoveDisplay():
	if heartBox.get_child_count() > 0:
		heartBox.get_child(0).queue_free()

and it works fine ! When I loose hp, it removes one heart. This function is getting called in the same script (The code for decreasing of hp is in the same player script so no issue there). But when it comes to increase of hp via a powerup, the code for that is attached to other scene of type Area2D. Now I can’t find any way of calling the heartDisplay function when my hp increases. (As you know I tried above two methods and got nothing)
Do you think there’s any way for me to know if my score variable is increasing ?

For example something like this: If my score increases, then I call the heartDisplay

If I can achieve something like this I can make the call from the same script and get desired result. My score is a singleton so I have no problem accessing it.

Scavex | 2021-01-05 17:08

I found a solution ! I just added the health scene in a group and named it "healthpowerup"
and using this I just added this little code in my player script :

if area.is_in_group("healthpowerup"):
	global.armor += 1
	heartDisplay()

and now it’s working ! The heart is getting added just the way I want !

Scavex | 2021-01-05 17:34

i’m glad you found a solution :slight_smile:

in general, you can call functions from wherever: you dont need any fancy arrangement of containers/group, but you have to specify the node in which the script with the function you need is present.

For example, you can place the hearthDisplay() function in the player node (as you did in the beginning), and in the powerup node script you can go with

var player=get_node(tree_path_to_PlayerNode) #something like "/root/Main/PlayerNode"
player.heartDisplay()

Andrea | 2021-01-05 18:49