How do I play a random audio after every index in an Array?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By hudadev


I am currently trying to make a dialogue system for my game. I wanted to implement a feature so it would play random audios after each word in the dialogue. So, I turned the text into an array, so each word is seperated. Any idea on how to play an audio for each word in the array? (Side note: I have all the different audios saved)

var test= $Control/text.text.split(" ")

here you can see I have split up my text into an array using String.split()…
Would I use a for loop?
Sorry if this is a dumb question, I am fairly new to programming!

btw, this is my entire script:

   extends Node2D

   signal finished_talking

export var dialogPath = ""
export(float) var textSpeed = 0.05
var dialog

var phraseNum = 0
var finished = false
onready var text = get_node("Control/text").text

func _ready():
	$Control/Timer.wait_time = textSpeed
	dialog = getDialog()
	assert(dialog, "Dialog not found")
func _process(_delta):
	if $".".modulate != Color("00ffffff"):
		var words = text.split(" ")
		for word in words:
			$Gus.playing = true

		$Control/Indicator.visible = finished
		if Input.is_action_just_pressed("ui_accept"):
			if finished:
				$Control/text.visible_characters = len($Control/text.text)
func getDialog() -> Array:
	var f =
	assert(f.file_exists(dialogPath), "File path does not exist"), File.READ)
	var json = f.get_as_text()
	var output  = parse_json(json)
	if typeof(output) == TYPE_ARRAY:
		return output
		return []
func nextPhrase() -> void:
	if phraseNum >= len(dialog):

	finished = false
	$Control/text.bbcode_text = dialog[phraseNum]["Text"]
	$Control/text.visible_characters = 0
	while $Control/text.visible_characters < len($Control/text.text):
		$Control/text.visible_characters += 1

		yield($Control/Timer, "timeout")	

	finished = true
	phraseNum += 1

func _on_Main_zoom_gus():

hudadev | 2021-06-22 18:38

If you would use a for loop. You would probably end up hearing just the sound for the last word. Instead you need to play one sound at a time and wait for it to finish and then play the next sound.

StopNot | 2021-06-23 05:58

:bust_in_silhouette: Reply From: StopNot

Here is a standalone example that plays a random sound for each string in an array. For the setup you need a new ui scene. Add a control node as the root and an audio stream player under it. Attach the following script to the control node.

extends Control

onready var audio = $AudioStreamPlayer

onready var sound_1 = preload("res://assets/sfx_sounds_Blip1.wav")
onready var sound_2 = preload("res://assets/sfx_sounds_Blip2.wav")
onready var sound_3 = preload("res://assets/sfx_sounds_Blip3.wav")
onready var sound_4 = preload("res://assets/sfx_sounds_Blip4.wav")

var sounds : Array
var words = ["this", "is", "a", "demo"]

func _ready():
     # connect audio play finished signal to _on_audio_finished function
	audio.connect("finished", self, "_on_audio_finished")
    # randomize to make sure our random numbers are always random
    # an array of all sounds
	sounds = [ sound_1, sound_2, sound_3, sound_4 ] 
    # play a random sound 

func _play_random_sound():
    # get a random number between 0 and 3
	var sound_index = randi() % 4 
    # get a sound with random index
	var sound = sounds[sound_index] 
    # set the sound to the audio stream player = sound 
    # play the sound 

func _on_audio_finished():
    # remove and print the first word in the array
    # pause for one second
	yield(get_tree().create_timer(1), "timeout") 
    # if there are words left in the array we continue
	if words.size() > 0: 
        # play a random sound again

When you run the code it will print the following output:


A random ‘blib’ is played after each word.

Not sure if this is what you want to achieve but hopefully it helps.

Hi! Thank you so much for this. One question :
How can I use an array from the main scene?
I used a JSON file to set the dialog and then split the text up to an array so it isn’t just one set of words. Do you think I should make a global variable so I can access it? Thanks again :smiley:

hudadev | 2021-06-23 16:43

I would add an autoload “global” node called events. Add a signal there. Connect my script to that signal and then emit signal from your main script. I can give you a full example later. I’m on mobile at the moment.

StopNot | 2021-06-23 16:54