Dealing damage to Player from another node

Godot V.4.2.2

I’m trying to make pop up Quiz when player collecting coins in my game and my method to show the Quiz node is using signal.

#Player.gd
extends CharacterBody2D
class_name Player

@export var speed = 150
@export var jump_force = 300
@export var gravity = 15
@export var life: int = 3

@onready var ap = $AnimationPlayer
@onready var sprite = $Sprite2D

var score: int = 0

func _ready():
	GameManager.player = self
	#Show HP Bar when starting the stage
	Signals.emit_signal("player_life_changed", life)
	Signals.score_increase.connect(scoreplayer)
	$Dialogue.visible = false

func _physics_process(_delta):
	if !is_on_floor():
		velocity.y += gravity
	
	if position.y > 1000:
		damage(1)
		respawn()


#Player HP Mechanism
func damage(amount: int):
	life -= amount
	Signals.emit_signal("player_life_changed", life)
	
	if life <= 0:
		get_tree().change_scene_to_file("res://Scene/failed_menu.tscn")

func scoreplayer(amount: int):
	score += amount

#Respawn Stage Pertama
func respawn():
	GameManager.respawn_player()

#Coin1.gd

extends Area2D
class_name Coin

func _ready():
	body_entered.connect(_on_body_entered)

func _on_body_entered(body):
	if body.get_name() == "player":
		Signals.emit_signal("coin1_collected")
		queue_free()

#Quiz1.gd

extends Control

@onready var timer: Timer = $Panel/Timer
@onready var timer_label = $Panel/TimerLabel
@onready var quiz_close: Timer = $QuizExit
@onready var display_text = $Panel/QuestionLabel

var player : Player

func _ready():
	Signals.coin1_collected.connect(on_coin1_collected)
	hide()
	quiz_close.wait_time = 3
	quiz_close.one_shot = true
	timer.one_shot = true
	display_text.text = "Tahun berapa Syarif Abdurrahman Al-Kadrie lahir?"
	update_timer_label()

func _process(delta):
	if timer.time_left > 0:
		update_timer_label()

func _on_option_1_pressed():
	timer.stop()
	start_quiz_exit_timer()
	player.damage(1)
	display_text.text = "Jawaban Salah!"
	quiz_close.timeout.connect(_on_quiz_exit_timeout)

func _on_option_2_pressed():
	timer.stop()
	start_quiz_exit_timer()
	player.damage(1)
	display_text.text = "Jawaban Salah!"
	quiz_close.timeout.connect(_on_quiz_exit_timeout)

func _on_option_3_pressed():
	timer.stop()
	start_quiz_exit_timer()
	player.damage(1)
	display_text.text = "Jawaban Salah!"
	quiz_close.timeout.connect(_on_quiz_exit_timeout)
	
func _on_option_4_pressed():
	timer.stop()
	start_quiz_exit_timer()
	Signals.emit_signal("score_increase", 200)
	display_text.text = "Jawaban Benar!"
	quiz_close.timeout.connect(_on_quiz_exit_timeout)

func update_timer_label():
	timer_label.text = "Waktu: " + str(round(timer.time_left)) + "s"

func _on_timer_timeout():
	display_text.text = "Waktu habis!"
	player.damage(1)
	start_quiz_exit_timer()
	quiz_close.timeout.connect(_on_quiz_exit_timeout)

func start_quiz_exit_timer():
	quiz_close.start()

func _on_quiz_exit_timeout():
	hide()
	get_tree().paused = false

func on_coin1_collected():
	show()
	timer.start()
	get_tree().paused = true

for the signal i simply using

signal coin1_collected()

so when player walking through the coins, system will show the quiz node then player should choose the options available within time limit.
When player choose the wrong answer, player will get 1 damage. But this mechanism is not working, nothing happens when player choose the wrong answer and i get error like
“Invalid call. Nonexistent function ‘damage’ in base ‘Nil’.”

Can someone help me solving this problem, thanks in advance

try:

func on_coin1_collected():
player = GameManager.player # Set the player reference
show()
timer.start()
get_tree().paused = true

1 Like

thanks bro