0 votes

hi. this is my first day with the engine and my coding skills are very poor. i'm trying to play a random sound when the previous one stops, but i can't make it. i got a "control" node and 4 audiostreamplayer nodes as childs, "s1", "s2", "s3" and "s4". my control node code is this:

extends Control

var a = RandomNumberGenerator.new()
var sound = 0

func _ready():
var sound = a.randi_range(1,4)

func _process(delta):
if get_node("s"+str(sound)).is_active == false:

the first part of the code works... it randomly plays one of the 4 sounds at the beginning of the scene. i don't now if this is the best way to do it, but it's the way that i found :P
the problem is that i can't make that when that first sound stop, another one start. the conditional "if getnode("s"+str(sound)).isactive == false:" give me the error "invalid get index 'is_active' (on base: null instance)"
probably is a very noob mistake...

asked Jan 25 in Engine by lucas2606 (15 points)

2 Answers

+1 vote
Best answer

Another way to play a random set of sounds continually, one after another is via yield. You just need to pick a sound, play it, wait for it to finish (via yield) and then do it again. So, using bits of your above code, something like this:

var a = RandomNumberGenerator.new()

func _ready():

func playSound():
    var val = a.randi_range(1, 4)       # pick a valid random number
    var snd = get_node("s"+str(sound))  # select a sound
    snd.play()                          # play the sound
    yield(snd, "finished")              # wait for the finished signal
    playSound()                         # do it again
answered Jan 25 by jgodfrey (5,574 points)
selected Jan 26 by lucas2606

thanks for your answer! it works perfect

+1 vote

I leave you another alternative way: Use a single AudioStreamPlayer and preload the audio files with preload and put them in an array. Then use the Stream property of AudioStreamPlayer to assign each sound to it. AudioStreamPlayer has a signal that runs every time the playback ends. The problem may be, if you have many files, you have to preload each sound (although there are ways to obtain all the files in a folder: https://godotengine.org/qa/5175/how-to-get-all-the-files-inside-a-folder but I see it half complex and unnecessary for this case.).

extends Node2D
var sounds=[]

func _ready():

func sounds_random(s:Array) -> void:

func _on_AudioStreamPlayer_finished():
answered Jan 25 by estebanmolca (1,199 points)
edited Jan 25 by estebanmolca

Oh, if you are new, you may not know the godot signals, in that case, to connect the finished AudioStreamPlayer signal, select it and go to the Node tab in the properties panel, right next to the Inspector panel and you will see the signals below. Select the signal onAudioStreamPlayerfinished () and press connect below, in the panel that appears select the node where you have the script. The onAudioStreamPlayer_finished () function is automatically created in your script.

thanks! after a while trying to make it work I discovered the signals watching a sample project
your code works, but I used the yield option because I got a lot of audiostreams (I begun with 4 just for testing, but the idea is to have a lot more) each one with internal variables that I need to call

Yes, it's very good. What Yield does is pause the function until a condition is met, in this case it uses the same signal to resume. And you can do more things such as a fade in / out or use some random silence between sounds.

Thnx, this helped me to bring in some variation into my background sounds. Together with a randomized timer, with a few sounds I get a lot of variation and randomness in my scene.


Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.