Function connected to signal doesn't get called

Godot Version

Godot 4.0

Question

Hello, in my game i’m trying to call a function by connecting a signal and the signal is emitted when the enemy’s projectile touches the player but even when the projectile touches the player and the signal emitter in the function is called. The function that is connected to the signal isn’t called. These are my scripts:

player.gd:

extends CharacterBody2D

class_name Player

signal player_destroyed
@onready var ray_cast_2d = $RayCast2D
@onready var ray_pos = ray_cast_2d.position
@export var move_speed = 200
@onready var ShootingPoint = $PlayerSprite/ShootingPoint
@onready var ShieldSprite = $Shield
@onready var Power = preload("res://power_up.tscn")
#@onready var bullet_area_cshape:CollisionShape2D = $BulletArea/CollisionShape2D


var bullet_speed = 2000
var bullet_scene = preload("res://bullet.tscn")
var coin = preload("res://coin.tscn")
var bullet_amount = 1

var dead = false
var shield_on = false
var powerup
var isShooting = false
var targetPosition: Vector2
var shootDirection: Vector2
var BulletPosition: Vector2
var BULLET = bullet_scene.instantiate()
	

func get_input():
	look_at(get_global_mouse_position())
	
	var dir = Vector2.ZERO
	velocity = transform.x * dir * bullet_speed
	if Input.is_action_just_pressed("shoot"):
		shoot()

func _process(delta):
	global_rotation = global_position.direction_to(get_global_mouse_position()).angle() + PI/2.0

func _physics_process(delta):
	get_input()
	var direction = Vector2.ZERO
	var input = Input.get_axis("left", "right")
	
	if dead:
		return
	
	if Input.is_action_just_pressed("shoot"):
		if bullet_amount == 1:
			shoot()
	
	if Input.is_action_just_pressed("throw"):
		throw_coin()
	
	if input > 0:
		direction = Vector2.RIGHT
	elif input < 0:
		direction = Vector2.LEFT
	else:
		direction = Vector2.ZERO
		
	var delta_movement = move_speed * delta * direction.x
	
	position.x += delta_movement
	
	move_and_slide()

func kill():
	print("kill called")
	player_destroyed.emit()
	#move_speed = 0
	#if dead:
		#return
	#dead = true
	#$PlayerSprite.hide()
	#$GameOverScreen/GameOver.show()
	#z_index = -1
	#queue_free()

func restart():
	get_tree().reload_current_scene()

func shoot():
	$Muzzle.show()
	$Muzzle/Timer.start()
	$ShootSound.play()
	
	if isShooting:
		return
	
	isShooting = true
	targetPosition = get_global_mouse_position()
	shootDirection = (targetPosition - global_position).normalized()
	
	BULLET.start(ShootingPoint.global_position, rotation)
	get_tree().root.add_child(BULLET)
	BULLET.transform = ShootingPoint.global_transform
	
	await get_tree().create_timer(0.2).timeout
	isShooting = false
	bullet_amount -= 1

func throw_coin():
	targetPosition = get_global_mouse_position()
	shootDirection = (targetPosition - global_position).normalized()
	
	var COIN = coin.instantiate()
	COIN.set_coin(global_position, targetPosition)
	get_tree().get_root().call_deferred("add_child", COIN)
	
	await get_tree().create_timer(0.2).timeout


func _on_player_area_area_entered(area: Area2D) -> void:
	if area.is_in_group("size"):
		area.queue_free()
		BULLET.get_node("BulletArea/CollisionShape2D").scale = Vector2(3,3)
		BULLET.get_node("Sprite2D").scale = Vector2(3,3)
		$SizeTimer.start()
	elif area.is_in_group("shield"):
		area.queue_free()
		shield_on = true
		ShieldSprite.set_visible(true)
		$SpeedTimer.start()
	
	#if "InvaderShot" in area.name:
		#if shield_on:
			#print("shield touch")
			#area.queue_free()
		#else:
			#print("kill touch")
			#kill()
			#player_destroyed.emit()


func _on_size_timer_timeout() -> void:
	BULLET.get_node("BulletArea/CollisionShape2D").scale = Vector2(1,1)
	BULLET.get_node("Sprite2D").scale = Vector2(1,1)


func _on_speed_timer_timeout() -> void:
	ShieldSprite.set_visible(false)

invader_shot.gd:

extends Node2D

class_name ZombieShot

@export var speed = 200
@onready var player_scene = preload("res://player.tscn")

func _process(delta):
	position.y += speed * delta


func _on_area_entered(area: Area2D) -> void:
	var Players = player_scene.instantiate()
	if area.is_in_group("player"):
		print("shot entered")
		Players.kill()

life_manager.gd:

extends Node2D

class_name LifeManager

signal life_lost(lifes_left: int)

@export var lifes = 3
@onready var player: Player = $"../Player"
var player_scene = preload("res://player.tscn")


func _ready():
	(player as Player).player_destroyed.connect(on_player_destroyed)

func on_player_destroyed():
	print("player destroyed called")
	lifes -= 1
	life_lost.emit(lifes)
	if lifes != 0:
		player = player_scene.instantiate() as Player
		player.global_position = Vector2(556, 530)
		player.player_destroyed.connect(on_player_destroyed)
		get_tree().root.get_node("world").add_child(player)

The functions in player.gd and invader_shot.gd were called but the one in life_manager was not.

Hmm, did you test that it is connected with get_connections() or is_connected()? Also, did you try and connect it by changing the variable reference temporarily to a direct reference.

I dont know if you need to double type safe the connection. You already have a typed variable, then you connect the signal with a typed variable as type. It seems redundant.

The place i can see as a problem is in your invader_shot.gd

You create a new player instance here and call kill in this instance, but you never connected the player_destroyed signal on this new instance, also, you check if the area is in the player group so probably what you wanted to do is call the node that holds this area (what i suppose is the player).


Also in life_manager.gd, this (player as Player) is unecessary, you already typed the player variable to be a Player type so you don’t need to do this casting again.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.