Getting invalid get instance 'hp' (on base: 'null instance')

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

Hello guys. I am getting the above error when I am playing my game. Everything works fine when I fire the bullets on my enemy but for some reason when the health bar on enemy gets depleted I get the error mentioned above. I have scene named ‘Enemy’ and within it I have instanced another scene named ‘Health’ which contains the ProgressBar with the Script. I have created a variable named ‘hp’ in Enemy Script but I m not sure that why things are not working out with the Life Bar. This is the what I am using to actually get the value of ‘hp’ in the value of Life Bar:

extends ProgressBar

func _ready():
	pass

func _physics_process(delta):
	value=get_tree().root.get_node("World").get_node("Enemy").hp

and this is my dead function in ‘Enemy’ Script :

func dead():
	hp-=1
	if hp<=0:
		is_dead=true
		velocity=Vector2(0,0)
		$AnimatedSprite.play("Dead")
		$CollisionShape2D.disabled=true
		$Timer.start()

As I mentioned earlier, for some reason when the health bar of my enemy is getting depleted I am getting the error invalid get instance ‘hp’ (on base: ‘null instance’) and my game freezes.

:bust_in_silhouette: Reply From: rustyStriker

whether the path in the ProgressBar is wrong or the Enemy script doesnt have hp variable.
the debugger points the line crashing when an error occurs, might as well point that out with the full script

This is my Enemy Script :

 extends KinematicBody2D
const GRAVITY =10
export(int) var SPEED =30
const FLOOR=Vector2(0,1)

var velocity=Vector2()

var direction=1

var is_dead=false
export(int) var hp=10


func _ready() -> void:
	pass # Replace with function body.

func dead():
	hp-=1
	if hp<=0:
		is_dead=true
		velocity=Vector2(0,0)
		$AnimatedSprite.play("Dead")
		$CollisionShape2D.disabled=true
		$Timer.start()


func _physics_process(delta):
	if is_dead==false:
		velocity.x=SPEED*direction
		if direction == 1:
			$AnimatedSprite.flip_h=false 
		else:
			$AnimatedSprite.flip_h=true
		$AnimatedSprite.play("Corona")
		velocity.y+=GRAVITY
		velocity=move_and_slide(velocity, FLOOR)
	
	if is_on_wall():
		direction=direction*-1
		$RayCast2D.position.x*=-1
		
	if $RayCast2D.is_colliding()==false:
		direction=direction*-1
		$RayCast2D.position.x*=-1
		
	if get_slide_count()>0:
			for i in range(get_slide_count()):
				if "Player" in get_slide_collision(i).collider.name:
					get_slide_collision(i).collider.dead()


func _on_Timer_timeout() -> void:
	queue_free()

As you can see I have actually made hp variable and even used it. Also I realised that one error is that Node not found “Enemy” ! But how am I supposed to fix that. How can I actually make the progress bar’s Value equal to hp then ?

Scavex | 2020-04-14 18:02

I like to put the health bars on the instances themselves so it will stick to them or under the enemy under a canvas layer so it will stay in place…

you can try to add a get_child(0) after the root to have this

 value = get_tree().root.get_child(0).get_node("World").get_node("Enemy").hp

since get_tree().root returns the root viewport and not the actual root you wanted ( like the game controller or whatever )

rustyStriker | 2020-04-14 19:38

It’s weird. I actually fixed the issue. I had several copies of my enemies created with names like Enemy, Enemy1, Enemy2 and so on. I deleted all other copies of Enemy and now everything works. But the issue now is that am I supposed to created the same enemy manually for my current scene again and again ? if we suppose that I need my Enemy 13 or 14 times in stage 1, for example those weird mushroom characters in Mario on which we used to jump. I actually tried creating copies of my enemy node again but when I kill even one enemy all other die and the life bar on them gets depleted simultaneously. Sorry if I’m asking too much but I’m new to it and it’s very perplexing

Scavex | 2020-04-14 19:45

had the same issue once trying to make a cube thingy fun project.
if you export a variable it makes it static between instances(through code or something, works really weird), and if you dont know a static variable means you have only one copy of it, so all of your enemies shared the same variable for health.

if you want to set their starting health not through code you can export a variable that will hold only the value of their maximum health and set their hp to the maximum health at the _ready call

rustyStriker | 2020-04-15 07:06

Hey, could you post how your node setup looks like? If your health bar is under your enemy node, you can just self.get_parent().hp for example, you really shouldnt call nodes by their name.

RazorSh4rk | 2020-04-17 10:06