GML [SOLVED] Dialog System Woes

Zahk

Member
I'll start by saying I'm a beginner - I'm only just starting to get the hang of GML, and I hesitate to even say that, especially given my current predicament.

I'm using a version of the dialog system created by Heartbeast in his RPG tutorial videos from a few years ago, which I've modified to suit my purposes. Almost everything is finally working as I intended - after days of agonizingly slow progress as I struggled to grasp and alter the code - but I just noticed that there seems to be a strange threshold of printed text that the draw_GUI event needs to reach before the player can continue to the next message/step of the array. That would be fine if that threshold were the end of the string, just like my code seems to say, but for some reason it's about halfway through a full dialog box. If the string is only a few words, the game doesn't recognize that the 'confirm_key' is pressed to continue to the next stage of the array for a couple of seconds after the string is finished printing. If the visible string passes this inexplicable threshold, the player can skip to the next step of the array before the current string has finished printing. Though I can explain that this is happening, I can't explain why, because the code seems like it should be working as intended to me. So, instead of throwing in the towel, I've come here for help.

The code is sprawled out over a few scripts and objects, so I'll just try to include the parts I believe are relevant:

This is in scr_talk_state, which is in the player's step event. "speaker" is the NPC instance:
Code:
with (speaker) {
    //Turn the sprite
    if (x > obj_player.x) {
        sprite_index = left_sprite;
    } else if (x < obj_player.x) {
        sprite_index = right_sprite;
    }
    if (y > obj_player.y) {
        sprite_index = up_sprite;
    } else if (y < obj_player.y) {
        sprite_index = down_sprite;
    }
         
    if (!instance_exists(dialog)) {
        dialog = instance_create_depth(camera_get_view_x(view_camera[0]), camera_get_view_y(view_camera[0]) + camera_get_view_height(view_camera[0]), 0, obj_dialog_box);
        dialog.text = text;

    } else {
        if (obj_player.confirm_key and dialog.text_count >= string_length(dialog.text[text_page])) {
            dialog.text_page++;
            dialog.text_count = 0;
            if (dialog.text_page > array_length_1d(dialog.text)-1) {
                sprite_index = default_sprite;
                with (obj_player) {
                    speaker = noone;
                    state = scr_move_state;
                }
                with (dialog) {
                    instance_destroy();
                }
            }
        }
    }
}
And this is in the Draw GUI event for the dialog box (obj_dialog_box):
Code:
if (string_char_at(text[text_page], text_count) == " ") {
    last_space = text_count;
} else {
    last_space = noone;
}

if (last_space != noone) {
    var text_words = scr_string_copy_words(text[text_page], 1, text_count);
 
    if (string_width(text_words)*display_scale >= width-(xmargin)) {
        //Remove the space
        text[text_page] = string_delete(text[text_page], last_space, 1)
 
        //Add a return. Using "\n" will enter a return (like pressing enter)
        text[text_page] = string_insert("\n", text[text_page], last_space);
    }
}


text_visible = string_copy(text[text_page], 0, text_count);

var xx = (x - camera_get_view_x(view_camera[0])) * display_scale;
var yy = ((y-48) - camera_get_view_y(view_camera[0])) * display_scale;

draw_text_ext_transformed(xx+xmargin, yy+ymargin, text_visible, 8, width, display_scale, display_scale, image_angle);

if (obj_player.confirm_key_held) {
    spd = .99;
} else {
    spd = .5;
}
text_count += spd;
If you need to see more, please let me know. Any and all help is appreciated; I desperately want to be done with this so I can finally move on to the rest of the game, without worrying about the damn dialog system.
 
Last edited:

Zahk

Member
I'm guessing that it's something to do with the if statement:
Code:
if (obj_player.confirm_key and dialog.text_count >= string_length(dialog.text[text_page]))
especially since I tried to use basically the same check to create an instance in the step event of obj_dialog_box, and that didn't work correctly either... but I don't see what's wrong with it.
 

Zahk

Member
Gonna throw in the Create event for the dialog box, for good measure:
Code:
depth = -1000;
text = noone;

text_visible = "";

text_page = 0;

text_count = 0;

spd = .5

display_scale = display_get_gui_width()/camera_get_view_width(view_camera[0]);

width = sprite_width*display_scale
xmargin = 10*display_scale;
ymargin = 8*display_scale;
 

Zahk

Member
Still having this issue! I did gather a little more information, however. The code
Code:
if (obj_player.confirm_key and dialog.text_count >= string_length(dialog.text[text_page])) {
            dialog.text_page++;
            dialog.text_count = 0;
            if (dialog.text_page > array_length_1d(dialog.text)-1) {
                sprite_index = default_sprite;
                with (obj_player) {
                    speaker = noone;
                    state = scr_move_state;
                }
                with (dialog) {
                    instance_destroy();
                }
            }
        }
Seems to run when text_count is greater than or equal to 50 and the player presses the confirm_key, and NOT when it is greater than or equal to the length of the string. As for why that is, I have no idea. Is it because checking for the string_length of an array variable just doesn't work correctly in gamemaker?

I tried slowing down the rate at which the text_count variable increases, but no matter how fast or slow I make it, it's only when that variable reaches 50 or more that the code will run when the key is pressed.

I'll also add that I printed the variables text_count and string_length(text[text_page]) to the screen so I could see the numbers, and string_length(text[text_page]) prints as the actual number it should be, not 50.
 
Last edited:

FacesOfMu

Member
Hi Zahk,
I'm a beginner, too, and glad to hear others can also spend large amounts of time nutting out small sections of code, too! ;)

I'm wondering about here:
Code:
   if (!instance_exists(dialog)) {
       dialog = instance_create_depth(camera_get_view_x(view_camera[0]), camera_get_view_y(view_camera[0]) + camera_get_view_height(view_camera[0]), 0, obj_dialog_box);
       dialog.text = text;
Where does the script get text from for the end of this line?
Code:
dialog.text = text;
And my second question: Are you expecting text to appear at a rate of 30 characters per second? That's what I gather from spd = 0.5 and an assumed room speed of 60. I'm sorry if I misunderstand.
 

Zahk

Member
The text variable comes from the speaker instance, which in this case is an NPC object. It's an array with a string input.

And yes, text currently appears at a rate of 30 characters per second - unless you hold down the confirm_key, which speeds up the rate the text appears.
 

Zahk

Member
Here's the create event of the speaker object where the text array is defined:
Code:
///initialize NPC
event_inherited();
dialog = noone;
text_page = 0;
default_sprite = spr_mom_right;
left_sprite = spr_mom_left;
right_sprite = spr_mom_right;
up_sprite = spr_mom_up;
down_sprite = spr_mom_down;
text[0] = "This text exists to test the functionality of the dialog box.";
text[1] = "I guess I will increase the amount of text to see if it makes a difference. I am extending this text to further test the extent of this bug";
text[2] = "Insert text here.";
 

Zahk

Member
Shouldn't it be like this?
Code:
string_length(dialog.text[dialog.text_page])
...you are my hero. I've been stuck here for days. DAYS. I could KISS you!

I still don't understand why the check was going through when text_count reached 50... but whatever, I guess it doesn't matter now.

Thank you SO much.
 

Lady Glitch

Member
Glad to help :)
I still don't understand why the check was going through when text_count reached 50...
It seems like you have another variable called text_page in your speaker instance which leads your script to the wrong point in the array.
 

Zahk

Member
Okay, yes, I figured it out - I was confused because text_page was set to 0 by default, and I thought it might be the length of the first index of the array, but it wasn't exactly 50, so I added a bunch of characters to the string and that increased the threshold.

What a relief! Thank you again!
 

FacesOfMu

Member
Thanks for your reply. It does look like a doozy.
What happens if the text itself is shorter than 50 characters? Does your "next page" code ever run? (as in, it never meets the strange threshold of 50)


Edit: didn't refresh my page and see the answers posted :)
 
Top