GML Adding sound effects to my text engine

Hey so my text engine thing works fine and all, but I'm having trouble making a sound play every time a letter appears on screen since the time function doesn't stop after the text finishes, could anybody help me figure out how to make it stop when the string is done writing? I tried things to do with string lengths but I had no luck.


Create:

GML:
begintext = false

draw_set_font(font0)

txt_num = 1

draw_set_color(c_white)

//this is how long the text can beeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee//

txt[1] = "It's just a useless lamp."

txt[2] = "yamp"

//put txt[3] = "hello" here to add another text.

txt1 = ""

time = 0

exited = true

textx = view_xview[0] + view_wview[0]/35

texty = view_yview[0] + view_hview[0]/1.5

textbox = false

endtextbox = true

textboxopen = false

Step:

GML:
if endtextbox = false{

textboxopen = false

if begintext = true{

if keyboard_check_pressed(ord("X")){

time = time + 100000

}

else{time = time + 2}

if keyboard_check_pressed(ord("Z"))

{

    time = 0

    txt_num = txt_num + 1

    global.textbox = true

    txt1 = ""

}



if txt_num < 2{

    global.canwalk = false

    global.textbox = true

}



if txt_num > 2{

    global.canwalk = true

    global.textbox = false

    textboxopen = false

    endtextbox = true

    textbox = false

}

else{txt1 = string_copy(txt[txt_num], 0, time/3)}}

if begintext = true{

obj_player.image_index = 0

}

}
 
Last edited:

Alice

Darts addict
Forum Staff
Moderator
First of all, please wrap your code in [code=gml][/code] BBCode tags. This will greatly improve the appearance and clarity of the code you post.

Second, your code could benefit from separating the dialogue handling from dialogue contents. In particular:
1. Defining the txt[] array could be done in something like instance's Creation Code, and then it could be passed to the dialogue manager object
2. Instead of comparing txt_num to 2, you could compare txt_num to array_length_1d(txt) (or array_length starting with GM:S 2.3, but from the tags it seems you still use 1.4). That way you adapt to however long the specific dialogue sequence is.
For that matter, you have txt_num < 2 in one condition and txt_num > 2 in another conditions, so neither handles txt_num == 2. Is that intentional? ^^'

Well, there are a lot of further ways this code could be improved, but it'd be too time-consuming to elaborate. We all have been there at some point...

------------------------------

Anyway, in order to achieve what you want, you need to:
- determine how many new letters are added in this step
- play a sound depending on how many letters are added; I assume it's the same sound every time

When it comes to letters count, I'd consider two methods:

a) Keep track of previous number of letters, so that the number of new letters is [current letters] - [previous letters].
In your case, current letters seems to be "time/3", so previous letters would be "previous_time/3", where previous time is the time at the beginning of step event, before more time was added.
But wait! The number of letters is limited, so it's actually min(string_length(txt[txt_num]), time/3) and min(string_length(txt[txt_num]), previous_time/3), respectively!
If you subtract one from another, you'll get the number of new letters. Moreover, with the "min" function in place no new letters will be reported once you reach the end of text!

b) More advanced, but ultimately much more flexible: specifically process each letter one by one, when its time comes. This is how I'd usually implement letter-by-letter typing.
Basically, instead of incrementing "time" variable, you decrement "time_till_next_letter" variable, whether by 2 or by 10000 or some other number depending on the situation.
While it's 0 or below and there are still letters left, you append a new letter to the text, increment the timer by some value (e.g. by 3) and possibly do other things, such as increasing the new letters counter by 1. I write "while", because if the timer goes low below, there can be multiple letters typed in the same step.
The advantage of individual letter processing is that you can treat some characters in a special way. For example, you might choose not to increase the time_till_next_letter variable on typing space/newline (and possibly omit sound for this, too). You might also want to add longer timeouts for commas and periods, making the typed dialogue resemble actual speech a little more.

When it comes to playing the sound itself, you can opt for several options:
- just play the sound whenever a number of typed letters is greater than 0
- for each letter added increase the volume of the sound (e.g. 50% volume for single letter, 75% for two, 87.5% for three and so on); I don't think it works so well with the dialogue
- play the sound when new letter is typed, but then set a cooldown and don't play the sound until cooldown passes; I think it's actually the best option for the dialogue, because you can expect letters to be typed out frequently, which can result in an unpleasant stream of sounds played at once; the cooldown can ensure that dialogue typing sounds are played at reasonable rate

I didn't mention playing sound N times for N letters, because it'll be too loud and awful, don't do that.

I hope you can figure things out from there. ^^
 
First of all, please wrap your code in [code=gml][/code] BBCode tags. This will greatly improve the appearance and clarity of the code you post.

Second, your code could benefit from separating the dialogue handling from dialogue contents. In particular:
1. Defining the txt[] array could be done in something like instance's Creation Code, and then it could be passed to the dialogue manager object
2. Instead of comparing txt_num to 2, you could compare txt_num to array_length_1d(txt) (or array_length starting with GM:S 2.3, but from the tags it seems you still use 1.4). That way you adapt to however long the specific dialogue sequence is.
For that matter, you have txt_num < 2 in one condition and txt_num > 2 in another conditions, so neither handles txt_num == 2. Is that intentional? ^^'

Well, there are a lot of further ways this code could be improved, but it'd be too time-consuming to elaborate. We all have been there at some point...

------------------------------

Anyway, in order to achieve what you want, you need to:
- determine how many new letters are added in this step
- play a sound depending on how many letters are added; I assume it's the same sound every time

When it comes to letters count, I'd consider two methods:

a) Keep track of previous number of letters, so that the number of new letters is [current letters] - [previous letters].
In your case, current letters seems to be "time/3", so previous letters would be "previous_time/3", where previous time is the time at the beginning of step event, before more time was added.
But wait! The number of letters is limited, so it's actually min(string_length(txt[txt_num]), time/3) and min(string_length(txt[txt_num]), previous_time/3), respectively!
If you subtract one from another, you'll get the number of new letters. Moreover, with the "min" function in place no new letters will be reported once you reach the end of text!

b) More advanced, but ultimately much more flexible: specifically process each letter one by one, when its time comes. This is how I'd usually implement letter-by-letter typing.
Basically, instead of incrementing "time" variable, you decrement "time_till_next_letter" variable, whether by 2 or by 10000 or some other number depending on the situation.
While it's 0 or below and there are still letters left, you append a new letter to the text, increment the timer by some value (e.g. by 3) and possibly do other things, such as increasing the new letters counter by 1. I write "while", because if the timer goes low below, there can be multiple letters typed in the same step.
The advantage of individual letter processing is that you can treat some characters in a special way. For example, you might choose not to increase the time_till_next_letter variable on typing space/newline (and possibly omit sound for this, too). You might also want to add longer timeouts for commas and periods, making the typed dialogue resemble actual speech a little more.

When it comes to playing the sound itself, you can opt for several options:
- just play the sound whenever a number of typed letters is greater than 0
- for each letter added increase the volume of the sound (e.g. 50% volume for single letter, 75% for two, 87.5% for three and so on); I don't think it works so well with the dialogue
- play the sound when new letter is typed, but then set a cooldown and don't play the sound until cooldown passes; I think it's actually the best option for the dialogue, because you can expect letters to be typed out frequently, which can result in an unpleasant stream of sounds played at once; the cooldown can ensure that dialogue typing sounds are played at reasonable rate

I didn't mention playing sound N times for N letters, because it'll be too loud and awful, don't do that.

I hope you can figure things out from there. ^^
thank you for replying, i'm super new to gamemaker and mess around with it time to time so i'm not amazing with figuring out stuff, but I'll try my best
 
update: I really couldn't figure out your message, I'm sorry. It's just too complex for me, but I have figured out a different way, I made it so the time += 2 only loops while txt1 != txt[current] and im going to make it so that when the time changes by like 4-8 it'll play the sound. it's probably not the best way but it's really the best I can do lol
 
Top