Can't play sound on death

Godot Version

4.2.1

Question

Hi, I’ve handled the sounds of a pistol who shots bullets, but when I try to play a sound at the death of the player, or a mob, the sound won’t play.
I’ve tested the sound elsewhere and when I move it out of their respectives functions, the sounds are playing well but won’t play when linked to the death of the mob nor the player.
When the mob dies, it uses queue_free(), and when the player dies, it emit a signal to the Game which then pause the game. (I’ve also tried to put the player death sound inside this function but it doesn’t work either).
My DeathSounds are child nodes of Mob and Player

Mob :

extends CharacterBody2D

var health = 3
var randomGen = randi_range(1,5)
var speed = 750.0

@onready var player = get_node("/root/Game/Player")

func _ready():
	%Slime.play_walk()
	if(randomGen == 1):
		$Slime.modulate = Color.from_hsv(1,0.8,0.8,0.8)
		$Slime.scale = Vector2(1.2, 1.2)
		health = 5
		speed = 500
		
	if(randomGen == 2):
		$Slime.modulate = Color(0.5,0.2,1,0.8)
		$Slime.scale = Vector2(0.8, 0.8)
		health = 1
		speed = 900

func _physics_process(delta):
	var direction = global_position.direction_to(player.global_position)
	velocity = direction * speed
	move_and_slide()


func take_damage():
	health -= 1
	%Slime.play_hurt()
	
	if health <= 0:
		$DeathSound.play()
		get_node("../../Game").score += 1
		
		const SMOKE_SCENE = preload("res://smoke_explosion/smoke_explosion.tscn")
		var smoke = SMOKE_SCENE.instantiate()
		get_parent().add_child(smoke)
		smoke.global_position = global_position
		queue_free()

Player :

extends CharacterBody2D

signal health_depleted

var health = 0.0
const SPEED = 1500

func _ready():
	$Music.play()

func _physics_process(delta):
	var direction = Input.get_vector("move_left","move_right","move_up","move_down")
	velocity = direction * SPEED
	move_and_slide()
	
	if (velocity.length() > 0.0):
		$HappyBoo.play_walk_animation() 
	else:
		$HappyBoo.play_idle_animation()
		

	const DAMAGE_RATE = 5.0
	var overlapping_mobs = %HurtBox.get_overlapping_bodies()
	if overlapping_mobs.size() > 0:
		health -= DAMAGE_RATE * overlapping_mobs.size() * delta
		%ProgressBar.value = health
		if health <= 0.0:
			health_depleted.emit()
			$DeathSound.play()

Game :

extends Node2D

var score = 0

func spawn_mob():
	var new_mob = preload("res://scenes/mob.tscn").instantiate()
	%PathFollow2D.progress_ratio = randf()
	new_mob.global_position= %PathFollow2D.global_position
	add_child(new_mob)


func _on_timer_timeout():
	spawn_mob()


func _on_player_health_depleted():
	%GameOver.visible = true
	%Score.text = str("Nombre de kills : " , score);
	get_tree().paused = true

Please format your code properly for easy reading.

My first guess is that your player node is getting freed before the sound plays. I assume $DeathSound is an audio stream player which is a child of the player node right? Without seeing your node setup, this is my assumption.
The way I personally handle sound especially on character death is to have my sounds play in autoload scripts that doesn’t get free when the character dies.

2 Likes

Sorry its my first post i didn’t know how to format the code but I edited it, and yes the sounds are childs nodes !

I tried to preload them with the @onready etc but it didn’t work either

Mob: b/c you do call queue_free() in the same frame as starting to play the sound. The mob object is freed before the start of the next frame, and with it goes the Deathsound stream player, so no sound. As FreakyGoose said - create an autoload that spawns AudioStreamPlayers as needed or a separate scene hosting players for specific sounds like Fencer shows in his video (Godot 4: Audio system tutorial). Up to you.

Player:
You need to set the DeathSound stream player that’s under Player node to have Process Mode of Always (in Inspector, on the right, at the bottom under Node)

2 Likes

Thanks for your reply, the player part worked well.

However I tried to do a SoundManager with an AUdioStreamPlayer2D as a child and this script for the parent Node :

soundManager.gd :

extends Node

@onready var mobDeathSound = $MobDeathSound

func playMobDeathSound():
	mobDeathSound.play()

Wich I then declared as an Autoload and enabled the global variable. But when I call it in my “mob” class :
SoundManager.playMobDeathSound()

I have an error : Attempt to call function “play” in base “null instance” on a null instance :
E 0:00:00:0808 soundManager.gd:3 @ _ready(): Node not found: “MobDeathSound” (relative to “/root/SoundManager”).
<C++ Error> Method/function failed. Returning: nullptr
<C++ Source> scene/main/node.cpp:1638 @ get_node()
soundManager.gd:3 @ _ready()

I don’t understand how it couldn’t find its own child

Assuming you implemented the manager as an autoload, can you show me what you assigned to it? You have to assign it a scene so that the audio player is instantiated alongside the manager.

It’s probably karma because you use camel case instead of snake case >.<

In all seriousness, though, I have no issues when trying this exact setup.

Then in some other scene:

func _ready():
	SoundMgr.play_mob_death_sound()

Im not sure to understand, how am I supposed to assign it ?

Lmao Im used to camel case sorry :stuck_out_tongue:

Well I don’t know why I have an issue, it must be silly but with the exact same setup I still have an error :

I’ve been on this for multiple days now, I just don’t understand, if you want I can make a video of my whole project to see if I’ve done something bad with the scenes and stuff but it’s kinda driving me crazy :frowning:

Just upload the project folder so we can download and check. Don’t include .godot folder inside.

Nevermind I deleted and made another audio manager and it worked

So the answers to my questions were :
1)At the player’s death, the node needed to have “Process Mode : Always”
2)Since the mob dies at the same time at the sound is played, it is requiered to have another node that manage it

Thanks alot for your answers, your answers were great but I failed in the execution.

1 Like

Glad it worked out! Godot is, great but… it has quirks.

I’m stuck on 4.2, for example, because upgrading to 4.2.1 or 4.3 dev1 or 4.3 dev 2 = game crashes on launch :sweat_smile: I’m just ignoring the problem hoping some update fixes it or until I REALLY need to figure it out.

1 Like

Btw since I have audio2D on mob death and its now managed by the audio manager, do you know a way to have that audio located thanks to the mob position ?

If the audio was a mob’s child node, the audio2D would have worked, but now that I manage my audio with an audio manager, it can’t keep track of the position of my entities

Godot has a solution just for this. Check this reply here: Advanced: good 2D audio architecture - #4 by mrcdk

btw, you don’t have to go this route. You CAN have audio as a child of the dying mob. You just separate the mob “dying” from the mob being removed from tree.

In my game, I do this to let the death animation play out, for instance. I.e. the mob emits signal that it died when it’s health hits 0, but then it plays death animation and/or particle effect (depends on mob), and only when one of those events finishes it calls queue_free().

When the mob emits “I died” signal, it’s removed from array of targetable enemies, it’s collision shapes are disabled, and the kill is added to the kill counter that’s shown to the player real-time. So for all intents and purposes, the enemy is gone… except for it’s remaining sprite/animation.

If you have a parent object take care of queue_free-ing your mobs, they could just emit 2 events: die, and release. And only on release - which emits after sound finishes playing - the mob is freed.

Ok I see, thanks alot for all your answers, its my first project in godot and I have a really small experience in game making, I’ll try to see what works best !

Pretty late for a reply, but there’s your mistake. Your node setup is in a scene, but you assigned a script as the singleton. Change it to the scene instead and it should work.

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