Playing Sound FX

Hello All,

I have just started with Godot but having problems with some of the concepts with the game engine. I did Unity some time back and while I recognise some of the concepts, others are completely alien to me.

Ok, I have a small character and using default features have a small character, moving around a platform “stage” using a tilemap. The thing I am trying to do is get the “hero” to collect coins supplied by the tilemap, the coins disappear when the character passes over them (Mario style) through the use of the a script that is called on the coin object/scene code below, but, the sound that I want to associate with the coin being “picked up” will not play. I made a AudioStreamPlayer scene with holdling just the Sound FX called pickupCoin but the script on the coin will not play the sound file.

func _on_body_entered(body):
var strBody = body;
#to see what hit the coin for error checking
print(strBody);
print (“+1 Coin”);

#play sound -> not working
$pickupCoin.play();

#remove the coin scene from screen
queue_free();

The error I receive is:

Attempt to call function ‘play’ is base ‘null instance’. on a null instance

So, I am hoping that someone will be able to point out what I am doing wrong.

If anyone can help here is a big “thankyou” in advance!

Regards.

A screenshot of the scene’s node tree might shed some light on it because $pickupCoin is a shortcut for a node called pickupCoin that should be a direct child node of the scene root. If it isn’t, the value will be null.

1 Like


Is this what you are after?

The “KillZone” feature is something I haven’t implemented yet so that’s the reason for the error warning.

Assuming the above code is in the coin scene, it does not know about the pickupCoin sound if you do it like this. You could make the pickupCoin node a child of the coin scene (“prefab”) and then drag the pickupCoin node (“component”) into the code window (holding ctrl) to get a reference.

I figured out what the problem was, but, not a solution. I needed the pickup node in every coin sound something I was trying to avoid AND the sound was not playing because the node/object was being destroyed causing the sound to not play because of it, a bugbear from my days in Unity.

So, I’ll just learn more about Godot features and revisit this topic in the very, very near future. I’m sure it will be easy to resolve, but, I have only been using Godot for 3 days :crazy_face:.

Thanks for replying

1 Like

If you are really determined to reuse the sound, you could probably get it working like so if you guarantee that all uses of them has them sharing a parent:

$"../pickupCoin".play()

I don’t know if this is the best way to do this but, it does seem to avoid the problems you mentioned in your later reply. Basically the … refers to the parent of the object. Everything else is pretty standard.
But I think the way to prevent having to reuse this a lot is probably a singleton. https://www.youtube.com/watch?v=bdsHf08QmZ4 This video seems helpful on this topic.

1 Like

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.

3 Likes

There is also the solution of (after an interaction) blocking any interactions with the coin + making it invisible, play the sound and only then call queue_free. I’m not sure what’s most elegant though.

Another alternative if you want to use only one AudioStreamPlayer node and don’t worry about the coin destruction is make use of polyphonic and groups.

  1. Create an AudioStreamPlayer node as child of your Game node and assign an AudioPlayerPolyphonic resource for the stream property, also mark the autoplay option
  2. Add this AudioStreamPlayer node to a group with a name you think fits better
  3. In your coin script, preload the sound effect you want to play
  4. When you want the sound to play, use this code:
var audio_playback_node = get_tree().get_first_node_in_group("group_name")
audio_playback_node.get_stream_playback().play_stream(the_loaded_audio_effect)
1 Like

That is “exactly” what I did in Unity! I was hoping to avoid that while I was learning about Godot and try and do it in the simplest way possible - it’s been a while between drinks.

As I learn a bit more I will implement that, but, it will take a while.

Thanks greatly for replying.

I was thinking the something along these lines as a quick workaround for now until I learn more about Godot. Like I said I haven’t been at this for very long.

Cheers.