• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Help with Dialogue Box!

Hi! I have been following tutorial of Peyton Burnham on Dialogue Boxes and I was planning to add my own things here and there but ran into a problem

I am trying to setup the system where I can setup a WAIT function and being able to edit how long the text should wait before continuing typing the text
for example:

scr_text("Damn...|wait=500|That sucks bro.")

I am trying to figure this out for 2 days now but still no luck, would really appreciate help xD

Here is the code if its needed:

obj_textbox Create Event:

GML:
//this is so the textbox is on top of everything
depth = -9999
//textbox parameters
textbox_width = 384
textbox_height = 128
border = 20; //so texts not pressed up against edges
line_sep = 24; //basically space between lines
line_width = textbox_width - border*2 //how long the line will be before it moves down
txtb_spr = spr_menu;
txtb_img = 0;

//the text
page = 0; //what page we are on
page_number = 0;
text[0] = "" //this is so we can make several texts
text_length[0] = string_length(text[0]) //checks how long the length is based on the text


char[0, 0] = "";
char_x[0, 0] = 0;
char_y[0, 0] = 0;


draw_char = 0; //how many of the characters are being drawn currently
text_spd = 1;
//options
option[0] = "";
option_link_id[0] = -1;
option_pos = 0;
option_number = 0;

setup = false; //check if the setup has been done

scr_set_defaults_for_text();
last_free_space = 0;
Step Event:
GML:
accept_key = keyboard_check_pressed(ord("Z"))

textbox_x = camera_get_view_x(view_camera[0])
textbox_y = camera_get_view_y(view_camera[0]) + 320;

//setup
if setup = false
{
    setup = true;
    draw_set_font(font_1);
    draw_set_valign(fa_top)
    draw_set_halign(fa_left)
   
    //loop thro the pages
    //p for page
    for(var p = 0; p < page_number; p++)
    {
        //find how many characters are on each page and store that number in the "text length" array
        text_length[p] = string_length(text[p]);
       
        //get the x position for the text box
            //no character (center the textbox)
            text_x_offset[p] = 128;
           
           
    //setting individual characters and finding where the lines of text should break
        //c is character
    for (var c = 0; c < text_length[p]; c++)
        {
           
            var _char_pos = c+1;
           
            //store individual characters in the "char" array
            char[c, p] = string_char_at(text[p], _char_pos);
           
            //get current width of the line
            var _txt_up_to_char = string_copy(text[p],1,_char_pos);
            var _current_txt_w = string_width(_txt_up_to_char) - string_width(char[c, p]);
           
            //get the last free space
            if char[c, p] == " " {last_free_space = _char_pos+1 };
           
            //get the line breaks
            if _current_txt_w - line_break_offset[p] > line_width
            {
                line_break_pos[line_break_num[p], p] = last_free_space;
                line_break_num[p]++;
                var _txt_up_to_last_space = string_copy(text[p],1,last_free_space);
                var _last_free_space_string = string_char_at(text[p], last_free_space);
                line_break_offset[p] = string_width(_txt_up_to_last_space) - string_width(_last_free_space_string);
            }
           
        }
        //getting each characters coordinates
        for (var c = 0; c < text_length[p]; c++)
        {
            var _char_pos = c+1
            var _txt_x = textbox_x + text_x_offset[p] + border;
            var _txt_y = textbox_y + border;
            var _txt_up_to_char = string_copy(text[p],1,_char_pos);
            var _current_txt_w = string_width(_txt_up_to_char) - string_width(char[c, p]);
            var _txt_line = 0;
       
        //compensate for string breaks
            //lb for line break
        for (var lb = 0; lb < line_break_num[p]; lb++)
            {
            //if the current looping character is after a line break
            if _char_pos >= line_break_pos[lb, p]
                {
                    var _str_copy = string_copy(text[p], line_break_pos[lb, p], _char_pos-line_break_pos[lb, p]);
                    _current_txt_w = string_width(_str_copy);
                   
                    //record the "line" this character should be on
                    _txt_line = lb+1; // +1 since lb starts at 0
                }
               
            }
           
            //add to the x and y coordinates based on the new info
            char_x[c, p] = _txt_x + _current_txt_w;
            char_y[c, p] = _txt_y + _txt_line*line_sep;
       
        }
    }
   
}



//typing the text
//its adding text spd until its text length
if draw_char < text_length[page]
{
    draw_char += text_spd;  
    draw_char = clamp(draw_char,0,text_length[page])
}


//---------------------flip thro pages------------------------------//
if accept_key
{
    //if the typing is done
    if draw_char == text_length[page]
    {
       
        //next page
        if page < page_number-1
            {
            page++;
            draw_char = 0;
            }
        //destroy textbox
        else
            {
            //link text for options
            if option_number > 0
                {
                create_textbox(option_link_id[option_pos]);  
                }
            instance_destroy();
            }
       
    }
    //if not done typing
    else
    {
        draw_char = text_length[page];
    }
}

//-----------------------draw the textbox-----------------------//
var _txtb_x = textbox_x + text_x_offset[page];
var _txtb_y = textbox_y
txtb_spr_w = sprite_get_width(txtb_spr);
txtb_spr_h = sprite_get_height(txtb_spr);
//back of the textbox
draw_sprite_ext(txtb_spr,txtb_img,_txtb_x,_txtb_y,textbox_width/txtb_spr_w,textbox_height/txtb_spr_h,0,c_white,1)


//-----------------------options------------------//
if draw_char = text_length[page] and page == page_number-1
{
   
    //option selection
    option_pos += keyboard_check_pressed(vk_down) - keyboard_check_pressed(vk_up)
    option_pos = clamp(option_pos, 0, option_number-1);
   
    var _op_space = 30;
    var _op_bord = 10;
    for (var op = 0; op < option_number; op++)
    {
    //the option box
    var _o_w = string_width(option[op]) + _op_bord*2
    draw_sprite_ext(txtb_spr, txtb_img, _txtb_x + 16,_txtb_y - _op_space*option_number + _op_space*op, _o_w/txtb_spr_w, (_op_space-1)/txtb_spr_h, 0, c_white, 1)
   
    //the arrow
    if option_pos == op
    {
        draw_sprite(spr_textbox_arrow,0,_txtb_x,_txtb_y+5 - _op_space * option_number + _op_space*op);
    }
   
    //option text
    draw_text(_txtb_x + 16 + _op_bord, _txtb_y+2 - _op_space*option_number + _op_space*op + 2, option[op]);
    }
}


//------------------draw the text--------------------//
//OLD CODE//

//var _drawtxt = string_copy(text[page], 1, draw_char);
//draw_text_ext(_txtb_x + border, _txtb_y + border,_drawtxt,line_sep,line_width);

for(var c = 0; c < draw_char; c++)
{
    draw_text( char_x[c, page], char_y[c, page], char[c, page] );  
}
SCRIPT scr_textbox_functions:

GML:
function scr_set_defaults_for_text()
{
    //two dimensional array, which is storing what positions should the text move to the next line
                                    //this can be 0 too
    line_break_pos[0, page_number] = 999;
    //this will keep track of the number of line breaks we have while looping thro the pages
    line_break_num[page_number] = 0;
    //this will help us keep track of things while we are loopin thro
    //width of the pixels we need to reset texts x position to
    line_break_offset[page_number] = 0;
}


/// @param text
function scr_text(_text){
    //every single page, it will correct defaults
    scr_set_defaults_for_text();

    text[page_number] = _text;

    page_number++;

}

/// @param option
/// @param _link_id
function scr_option(_option, _link_id){
    option[option_number] = _option;
    option_link_id[option_number] = _link_id
   
    option_number++
}


/// @param text_id
function create_textbox(_text_id){
    with(instance_create_depth(0,0,-9999,obj_textbox))
    {
        scr_game_text(_text_id);
    }
}
SCRIPT scr_game_text:

GML:
/// @param text_id
function scr_game_text(_text_id){
switch(_text_id) {
   
    //PLACEHOLDER TEXT
    case "npc 1":
        scr_text("Yeah...to be honest, I don't really get it.");
        scr_text("Why do people think that Bea is cool like for real Bea sucks what do you think is Bea cool?");
            scr_option("yeah, beas cool", "npc 1 - yes");
            scr_option("nah bea sucks", "npc1 - no");
    break;
    case "npc 1 - yes":
        scr_text("bea sucks...");
    break;
   
    case "npc1 - no":
        scr_text("ok cool cool");
    break;  
}
   
}
 
It doesn't appear like that functionality is in the code at all yet. So am I right in assuming that this functionality you want is not part of the tutorial?

Code:
//typing the text
//its adding text spd until its text length
if draw_char < text_length[page]
{
    draw_char += text_spd;  
    draw_char = clamp(draw_char,0,text_length[page])
}
This is the piece of code that is most relevant to your problem. Currently it increases draw_char every step by whatever text_spd is. So for your idea to function, you will need to implement something to parse out the |wait=500| and than when it reaches the appropriate spot, set text_spd = 0 for 500 steps. You could do this with another counter var that counts down for that number of steps. Something like this:

Code:
//typing the text
//its adding text spd until its text length
if draw_char < text_length[page]
{
    if text_wait <= 0
    {
    draw_char += text_spd;  
    draw_char = clamp(draw_char,0,text_length[page])
    }
    else
    text_wait--;
}
So that part is simple. The harder part is parsing the string, getting the command |wait=500| and setting text_wait = 500 at the exact right character.

I can think of a few ways to do this. But to make it compatible with the code here, I'd suggest including it in this for loop:
Code:
//setting individual characters and finding where the lines of text should break
        //c is character
    for (var c = 0; c < text_length[p]; c++)
        {
...
Basically to parse the string, you need to cycle through every character in the string, than when you find a | symbol, you than want to check the next few characters for a command, in this case "wait", once you have met the condition, you grab the value on the other side of the = symbol, in this case 500, and than store that value in a variable, let's call it text_wait_time[0]. You will also need a variable to keep track of when this wait time should be applied, let's call that text_wait_position[0], this will be a character position in the string.

When all that is done, you can than add to that first section again:
Code:
//typing the text
//its adding text spd until its text length
if draw_char < text_length[page]
{
    if text_wait <= 0
    {
    draw_char += text_spd;  
    draw_char = clamp(draw_char,0,text_length[page])
    }
    else
    text_wait--;

    if text_wait_position[i] == draw_char and text_wait == 0
    {
    text_wait = text_wait_time[i];
    i++;
    }
}
The reason I made text_wait_position[0] and text_wait_time[0] arrays is because you may have more than 1 command in a single string so you will need to keep track of the different positions and timings you may need. Also keep in mind you will need to parse out the commands from the string itself, so the |wait=500| command in the string needs to be completely removed, than grab the position, than move forward to find the next one. Hopefully you understand enough about the string functions cause you are gonna be using them a lot to implement this.

This is all the help I can provide, anymore would take a lot of time and testing on my end but hopefully this gives you some ideas on how to approach this. Parsing strings isn't too bad but you gotta be real careful with it, mistaking character index positions and such can cause some really nasty bugs that are hard to test and solve for. I recommend trying to simplify the command process, instead of |wait=500| just do something like a single special character, let's say ^ symbol means to wait 1 second. You are very unlikely to use that symbol in dialogue so it shouldn't be a big loss. You can than also have another symbol like * that means wait 2 seconds. This will make parsing a lot easier, as you only gotta compare one character, set the variables, remove that one character and than continue the loop.

Anyway that's all I got. Good luck. đź‘Ť
 
Top