0 votes


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!

Godot version v3.2.3
in Engine by (48 points)

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 = File.new()
    assert(f.file_exists(dialogPath), "File path does not exist")

    f.open(dialogPath, 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():

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.

1 Answer

+1 vote

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
    audio.stream = 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.

by (80 points)

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 :D

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.

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.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.