Newbie - struggling with coin pick up sound

Godot Version

4.2.2

Question

So, I am very new to programming in general, but for the past couple of days I have been trying to make some games in godot.

I followed this tutorial https://www.youtube.com/watch?v=LOhfqjmasi0 by Brackeys, but I have since tried remaking the whole thing without looking at the tutorial and instead using the breadcrums of knowledge that I remember to force my brain to learn some of the concepts and allow me to fully understand the why behind each line of code. Also so that I could experiment and try different things.

On the subject of that last point, I got to the point where I was doing a sound effect for picking up a coin and wanted to see if I could do it differently to how he does it in the video, but was struggling because obviously as soon as queue_free() happens the coin disappears and the sound effect isnt played. I thought if I just put it in like this:

@onready var coin_sound= $coin_sound

func _on_body_entered(body):
	if body.name == "player":
		coin_sound.play()
		queue_free()

That it should work because it would play the sound and then make the coin disappear, but obviously its doing it so fast that the coin still disappears before the sound can play. I still want the coin to vanish the moment the player touches it, so I thought I could tie the sound to the player, so that when it entered the body of the coin the sound would technically come from the player but it would seem right hopefully and then tried this:

@onready var coin_sound= $coin_sound

const COIN = preload("res://Scenes/coin.tscn")

func _on_area_2d_body_entered(body):
	if body.name == COIN:
		coin_sound.play()

I created an area2d node in the scene for the player and gave it a collision shape 2d and connected the _on_area_2d_body_entered function and the sound effect etc, and ctrl+click and dragged the scene for the coin in to create that constant, however when I run the game it just immediately crashes. Which is whatever since it seemed like a messy way of doing things.

Finally I found this post Playing Sound FX where the solution is from someone called FencerDevLog, and the solution was this:

In our game, I use a solution that relies on a global autoload class called
SoundManager, where I keep all sound effects in one place. It can be called
from anywhere, and the sound will always play in full regardless of the
existence of the corresponding game object.

extends Node

@onready var pickup_coin = $PickupCoin
@onready var toilet_flush = $ToiletFlush
# more sounds to add here

func play_sound(key):
	var sound = get(key)
	if sound is AudioStreamPlayer:
		sound.play()
	else:
		print("Sound " + key + " not found!")

Then you can use this from anywhere:

SoundManager.play_sound("pickup_coin")

And, of course, don’t forget to add SoundManager to Project Settings >
Autoload.

However when I tried this, it just says that “Identifier “SoundManager” not declared in the current scope” and I dont know what else to do. I tried making sure that the sound manager is in the main game scene and when that didnt work I tried putting the sound manager into the scene with the coin, but then it just said the same thing, but for the sound instead.

I assume its because I have to create it in a different way to how I think, but I cant for the life of me figure it out, even when reading through some of the documentation on singletons/autoload.

Sorry this has been a very long post, but is there any way of doing it other than what is in that tutorial?

edit*
I think I figured it out, not the best but I did this:

extends Area2D

@onready var coin_sound = $coin_sound
@onready var animated_sprite = $AnimatedSprite2D
@onready var collision_shape = $CollisionShape2D

func _on_body_entered(body):
	if body.name == "player2":
		animated_sprite.visible = false
		coin_sound.play()
		collision_shape.queue_free()
		await coin_sound.finished
		queue_free()

Technically the coin is still there so the sound plays, but the collision shape disappears so you cant interact with it multiple times. Finally after all of that is done, it finally gets rid of the coin.

Do like this:

func _on_body_entered(body):
    if body.name == “player”:
        pickupsound.play()
        await pickupsound.finished
        queue_free()

It looks like you missed the last line: And, of course, don’t forget to add SoundManager to Project Settings > Autoload.
Without that, the SoundManager prefix isn’t globally declared.

Yeah, the only problem with this is that this means that the coin doesnt disappear as soon as the player touches it. It plays the sound, but obviously even though the sound is very short the coin hangs around for half a second before disappearing. Ideally I was looking for an alternate way to do it so that the sound played but also the coin still disappeared the moment the player touches it.

Fortunately I figured out a different solution, however what that attempt I did in fact add it to the autoloader, which is partly why I was so confused. I was at least somewhat familiar with that bit since I had already done that with the music for the game. I might go back and look at it again at some point to see if I can figure out why it didnt work for me. Unless someone else has an idea of why.

You can create a animation on coin disappear like it’s sprite modulate a moves to 0 in that animation so in mean time, the sound will also play and after its end it will queue free, here is the demo you can check it.

Just realized you are the friendly fellow who made that origional solution. Out of curiosity I got rid of my solution and tried again to make this. I created a new scene with a default node (not a 2d node or anything). I then put the code in like this:

extends Node

@onready var pickup_coin = $AudioStreamPlayer2D

func play_sound(key):
	var sound = get(key)
	if sound is AudioStreamPlayer:
		sound.play()
	else:
		print("sound " + key + " not found!")

Then under the coin scene I put this:

extends Area2D

func _on_body_entered(body):
	if body.name == "player2":
		SoundManager.play_sound(pickup_coin)
		queue_free()

Then I made sure to do the autoload again, and this time that seemed to work better, but it still said ““pickup_coin” not declared in the current scope”. I made sure all the names and etc are all correct and line up too, so I am left scratching my head a bit.

Is there something extra I have to do for it to count the sound constant as part of the key?

Nope, it’s supposed to be a string. Don’t forget the quotes: SoundManager.play_sound("pickup_coin")

The string should match the variable name defined in SoundManager:
@onready var pickup_coin = $AudioStreamPlayer2D

1 Like

Sorry again, I was playing around with it and realized I had it set to, if sound is AudioStreamPlayer:, but I was specifically using the AudioStreamPlayer2D. I made sure to specify the 2D and it worked perfectly and is a far better long term solution to the janky thing I managed to put together!

Thanks so so much for your help, some of this probably could have been avoided if I hadnt been up all night lol.

Also just wanted to say, thanks for uploading all those tutorials on youtube, I was have a look through some of them and they look incredibly useful. Also looking forward to the game you are working on!

1 Like

You are 100% right, I feel a little silly for missing that.
Sorry to keep bothering you, but I have mostly got it working now, except that now it cant find the sound for some reason.
I have it set up like so:
Sound Manager

extends Node

@onready var pickup_coin = $pickup_coin



func play_sound(key):
	var sound = get(key)
	if sound is AudioStreamPlayer:
		sound.play()
	else:
		print("sound " + key + " not found!")

Coin

extends Area2D

func _on_body_entered(body):
		SoundManager.play_sound("pickup_coin")
		queue_free()

except it just returns the sound pickup_coin not found thing. I have deleted the node a few times and re done the whole thing and made sure it has a sound attached to the node and everything, and yet I still cant get it to work for some reason.

I feel like I cant see the forrest for the trees at the moment. So if you have the time, do you know what might be the problem now? I really appreciate your help!

Thank you!

1 Like