Pickup sound doesn't play

Godot 4.1

My pickup sound doesn’t work when the characterbody collides with the item (2d game). Everything else in the code works except for this

extends Area2D

@onready var gamemanager = %gamemanager
@onready var pickup = $pickup


func _on_body_entered(body):
	if (body.name == "CharacterBody2D"):
		queue_free()
		gamemanager.add_point()
		pickup.play()

the problem is that you remove the node with “queue_free()” and the sound is a child of the node and is therefore also removed. You can either put the sound to the gamemanager or reparent it before you delete the node. Just be careful that you also remove the soundplayer when you reparent it

1 Like

I agree with @herrspaten, but you can also use await. This should work:

In this case its good to know that your object exits until the sound is over and may still execute code or interactions

If you want to make a throwaway sound player, here’s how to do it so it cleans itself up:

  1. Create a file called sound.gd
  2. Add the code below to it.
extends Node


func play(sound: AudioStream):
	if sound == null:
			return
	var player = AudioStreamPlayer.new()
	Engine.get_main_loop().current_scene.add_child(player)
	player.set_stream(sound)
	player.play()

	var timer = LifetimeTimer.new(player)
	timer.wait_time = sound.get_length()
	Engine.get_main_loop().current_scene.add_child(timer)
	timer.start()
  1. Go to Project → Project Settings → Globals Tab
  2. Click the folder button next to Path.
  3. Navigate to the sound.gd file and select it.
  4. Click the +Add button.
  5. Create a second script called lifetime_timer.gd
  6. Add the code below to it.
class_name LifetimeTimer extends Timer


@onready var item


func _init(item_to_free: Variant):
	item = item_to_free


func _ready() -> void:
	self.timeout.connect(die)


func die():
	item.queue_free()
	queue_free()

Then, in your pickup.play() method, change it to a single line that calls Sound.play() and passes the audiostream you want to play. The sound will play and then the audiostream player will destroy itself. This allows multiple sound effects to play at once and overlap, as well as makes sure you don’t end up with a memory leak.

There is a law in programming that says that codes are executed one by one from top to bottom.
so , you just need to put the queue_freeon the bottom.
queue free removes nodes or data’s so when you remove the node , audio player gets remove too ! and there is no music file to play.
at first you should play the song , and then kill that !

the problem is that it wont wait until the sound is finished, instead it will be deleted the moment it starts

1 Like

queue_free() actually runs at the end of the current frame, regardless of where you put it in the code. I had the same assumption you did, and it took me a while to realize that this method works this way. Hence, the code above is a simplified version of my final solution to exactly this problem.

1 Like