1. Hey! Guest! The 35th GMC Jam will take place between November 28th, 12:00 UTC - December 2nd, 12:00 UTC. Why not join in! Click here to find out more!
    Dismiss Notice

GM:S 1.4 Hello To A Powerful Text Engine! ( NewExtra Video Added!)

Discussion in 'Tutorials' started by Xskode, Jun 22, 2016.

  1. Xskode

    Xskode Member

    Joined:
    Jun 21, 2016
    Posts:
    55
    GM Version: Studio 1 (may work with other versions)
    Target Platform: Windows (may work with HTML5 and mobile)
    Download: See links below ( Part 7 is at the bottom )
    Description: This textbox engine will allow you to create characters from nothing and give them a fully created dialogue within 9mins! Allowing you to make the story you always wanted your game(s) to have!

    This textbox is extremely dynamic!
    allowing you to setup cut-scenes! use different fonts per character
    and/or sentence! instantly make text scroll, highlight or appear!
    With this textbox engine you will be able to draw sprites (images) on the screen indicating who is speaking!
    And so much more!!

    Yes, Game Maker Studio now has a very powerful textbox engine and you get to be the first to use it!!

    This series will show you :
    how to create a very powerful textbox engine for your game(s)
    how to use the textbox engine
    how to add to the engine at anytime


    Part 1 of 6




    Part 2 of 6



    Part 3 of 6




    Part 4 of 6



    Part 5 of 6
     

    Attached Files:

    Last edited by a moderator: Apr 2, 2017
  2. Kazumo

    Kazumo Guest

    Useful tutorial, will totally need when I'll start my project. Also, your voice is great, made the tutorial super enjoyable.
     
    Xskode likes this.
  3. Xskode

    Xskode Member

    Joined:
    Jun 21, 2016
    Posts:
    55
    thanks appreciate the feedback! that really helps :)
     
    Kazumo likes this.
  4. SolarAnima

    SolarAnima Member

    Joined:
    Jun 26, 2016
    Posts:
    2
    Your text engine, while usable is in no way an engine. You are just copying a template made in a different object, witch is inefficient. Also copying switch statements like that makes me cringe. The code should look like this:
    Code:
    ///Drawing textbox and the text
    
    if(global.conversation)
    {
        depth = -10000;
        if(num <= num_max)
        {
            //Set the font!
            draw_set_font(fnt_textbox);
            //Background filler
            bg = draw_rectangle_colour(my_x2,my_y2,my_x2+string_width(speak[num]),my_y2+string_height(speak[num]),c_gray,c_gray,c_gray,c_gray,false);
            bg_outline = draw_rectangle_colour(my_x2,my_y2,my_x2+string_width(speak[num]),my_y2+string_height(speak[num]),c_black,c_black,c_black,c_black,true);
       
            //Drawing the actual text!
            draw_text(my_x2,my_y2,speak[num]);
            draw_text_colour(my_x2,my_y2,string_copy(speak[num],0,scroll_text),c_silver,c_white,c_white,c_white,255);
       
            //Drawing the -next- button on screen
            if(scroll_text >= string_length(speak[num]))
            {
                draw_text(my_x2 + string_width(speak[num]),my_y2+string_height(speak[num])/1.4,"-next-");
           
            }
            else
            {
                scroll_text += scroll_timer;
            }
           
            //Check if the player is proceeding with the conversation
            if(keyboard_check_released(ord(next_button)))
            {
                //Check if text is still scrolling
                if(scroll_text < string_length(speak[num]))
                {
                    scroll_text = string_length(speak[num]);
                }
                else
                {
                    if(num < num_max)
                    {
                        num += 1;
                        scroll_text = 0;
                    }
                    else
                    {
                        global.conversation = false;
                        conversation = false;
                    }   
                }       
            }
        }
        else
        {
            global.conversation = false;
        }
    }
    else
    {
        instance_destroy();
    }
    Then you can just use it in another object like so:
    Code:
    if(keyboard_check_released(ord("E")) && global.conversation == false && distance_to_object(obj_player) < 32)
    {
      new_convo = instance_create(x,y+64,obj_textbox);
      new_convo.speak[0] = "Hi!";
      new_convo.speak[1] = "My name is Margret!";
      new_convo.speak[2] = "I really like flowers,# do you happen to have any?";
      new_convo.num_max = array_length_1d(new_convo.speak) - 1;
      new_convo.conversation = true;
      global.conversation = true;
    }
    
     
  5. Xskode

    Xskode Member

    Joined:
    Jun 21, 2016
    Posts:
    55

    what you have is very great. however it lacks the ability to easily create dynamics within the current conversation.

    example:
    making something unlock when player reach sentence 9. or making the character repeat a certain line. or changing color of text and/or font just for one sentence.
    that is the reason for the - switch - you can then place all dynamics you want per sentence. and it's in a draw event so you can also add any type of drawing dynamics per sentence as well; like giving each npc there own
    textbox background color. this engine is very flexible and powerful. and i do believe it is an engine because you create the whole workflow and then call it a day. another thing about your code is you have to use 2 objects just to
    use the engine. with the one I designed, you only use the object(s) that you want to have text/talk.

    and the ability of saving the engine to a file allows you to not have to keeping writing the code over ( like one would have to do if using the code you just posted ) just to setup the flow structure before they can
    make their character start talking.

    as shown in the video. a character is fully setup, given sentences, given dynamics, etc... in less than 9minutes. which greatly gives the developer more time focusing on my the stroy and adding all kinds of dynamics
    than wasting time writing the same code before being able to work on the story.

    so yeah, I believe this is a very powerful textbox engine. and if you test it out you will find that it is very useful and helpful and time saving and powerful and dynamic.
     
    Piece0pie likes this.
  6. SoulTie

    SoulTie Guest

    This looks great. I admit that I did not watch all the videos, I just don't have the time for that today. I think I'll check them out soon. I'm sure the answer to this can be found in the videos, but do you have the ability to add different borders to the textbox? If not, I can add this in, but it would be a nice feature to include in the tut.
     
    Xskode likes this.
  7. Xskode

    Xskode Member

    Joined:
    Jun 21, 2016
    Posts:
    55
    my apology for the late reply. just got back from a client- and it took WAY LONGER than expected!
    anyways, yes you can add different borders to the textbox for the engine is setup to do so- however, I didnot show that in the video- instead I showed how you can add different background colors to the textbox and different text colors as well.

    But I will make a video tomorrow (which is later to day. it's 2am over here) showing how to change the border in a much better way and then I will upload it here and call it part 6.
    I will try not to make the video to long so you will be able to watch it fully. (but no promises, as I want to make sure that when one is done watching the video they know 100% how to use the engine and understands how it works)
     
  8. Xskode

    Xskode Member

    Joined:
    Jun 21, 2016
    Posts:
    55
    As was asked by SoulTie:
    "...but do you have the ability to add different borders to the textbox? If not, I can add this in, but it would be a nice feature to include in the tut. "


    Part 6 of 6 ( Bonus Video 1 of X )
     
    Last edited: Jun 28, 2016
  9. Xskode

    Xskode Member

    Joined:
    Jun 21, 2016
    Posts:
    55
    Inspired by Petra:
    "... if there was a way I could add shaky text to it in some way?"

    Here it is. Making a shaky text effect using the Textbox Engine!

    Part 7 of 6 ( Bonus Video 2 of X )


    Enjoy!
     
  10. BaristaGamer

    BaristaGamer Guest

    Hi, just a bit of a question before I watch your videos as I don't have much time, but will this kind of tutorial teach me how to do dialogue boxes and apply them to different objects?

    For instance, will I be able to have one object/NPC say one thing, and then be able to go to another NPC and have them say something else? I've ben trying to do this all weekend and I've had little success.
     
    Xskode likes this.
  11. Maria Love

    Maria Love Guest

    Indeed .Use Full tutorial , + subscribed
     
    Xskode likes this.
  12. Xskode

    Xskode Member

    Joined:
    Jun 21, 2016
    Posts:
    55

    Yes this tut will give you exactly what you're looking for :)
     
  13. Lucas Xavier

    Lucas Xavier Guest

    Hello, I used your engine because of the freedom it allowed me to manipulate events, however i would like to turn it into a scrollable textbox with a fixed size. However I am having some troubles with it, I tried to implement this guy

    It uses the ds_list_create function in game maker. The code turned out like this:

    Create
    Code:
    ///creating variables textbox
    
    ///when true draw text box and stop player from moving
    convo = false;
    global.Convo = false;
    
    c_obj = obj_player; ///check-object (the object game will check for within talk range)
    
    ///Setting location of textbox based on view
    mx1 = view_xview[0];
    my1 = view_yview[0];
    
    ///setting location of textbox based on talking person's location
    mx2 = x;
    my2 = y;
    
    ///setting location of the textbox on the bottom of the screen
    mx3 = view_wview[0]/4
    my3 = view_wview[0] - 680;
    
    ///setting location of textbox based on centering
    mx4 = view_wview[0]/2;
    my4 = view_wview[0] - 200;
    
    trange = 97 /// used for checking if player is within the talk range
    
    /// colors used for the background of the textbox
    c_calm = c_aqua;
    c_reg = c_black;
    c_angry = c_red;
    c_name = c_olive;
    
    ///colors used for text highlight
    sc_silver = c_white;
    sc_white = c_green;
    sc_green = c_white;
    sc_teal = c_white;
    
    ///buttons used to proceed or start convo
    talk_button = "E";
    talk_button2 = "MOUSE_BUTTON";
    next_button = "R";
    next_button2 = "MOUSE_BUTTON";
    
    /// if true player will receive an event after talking a certain amount of time
    hidden_event = false;
    hidden_event_count = 0;
    hidden_event_max = 5;
    
    /// used for making text scroll and highlight
    scroll_text = 0;
    scroll_timer = 0.5;
    
    /// creating a timer that syncs with the current scroll_timer speed
    
    seconds = 0;
    count_up = false;
    
    //Timers used to alter timer speed
    scroll_timer_sad = false;
    scroll_timer_slow = false;
    scroll_timer_regular = true;
    scroll_timer_fast = false;
    scroll_timer_scared = false;
    
    
    num = 1; ///used to select the next thing to say
    num_max = 3; ///used as the max amount of things character say
    
    ///used to tell when a part of the convo is reached
    convo_part_max = 50; /// max amount of parts of the conversation
    convo_part = 1; ///begining of the conversation
    
    ///List of everything the npc or characters will say
    
    ///part1
    speak[1] = "Hello, this is me and that is you. Right? Hello, this is me and that is you. Right?Hello, this is me and that is you. Right?Hello, this is me and that is you. Right?Hello, this is me and that is you. Right?";
    speak[2] = "I know you do not understand, but oranges are very tasty.";
    
    ///part2
    speak[3] = "Well, I did'nt ask you anything...";
    speak[4] = "Well...";
    speak[5] = "leave me alone...";
    speak[6] = "";
    speak[7] = "";
    speak[8] = "";
    speak[9] = "";
    speak[10] = "";
    speak[11] = "";
    speak[12] = "";
    speak[13] = "";
    speak[14] = "";
    speak[15] = "";
    speak[16] = "";
    speak[17] = "";
    speak[18] = "";
    speak[19] = "";
    speak[20] = "";
    speak[21] = "";
    speak[22] = "";
    speak[23] = "";
    speak[24] = "";
    speak[25] = "";
    speak[26] = "";
    speak[27] = "";
    speak[28] = "";
    speak[29] = "";
    speak[30] = "";
    speak[31] = "";
    speak[32] = "";
    speak[33] = "";
    speak[34] = "";
    speak[35] = "";
    speak[36] = "";
    speak[37] = "";
    speak[38] = "";
    speak[39] = "";
    speak[40] = "";
    speak[41] = "";
    speak[42] = "";
    speak[43] = "";
    speak[44] = "";
    speak[45] = "";
    speak[46] = "";
    speak[47] = "";
    speak[48] = "";
    speak[49] = "";
    speak[50] = "";
    
    
    width = 240;
    height = 120;
    padding = 8;
    
    // Keep track of the starting line
    start = ds_list_create( );
    ds_list_add(start, 0);
    
    // Keep track of the last space and current position
    count = 0;
    last_space = 0;
    line = 0;
    
    // Set the message
    
    str = "";
    
    Draw
    Code:
    ///drawing textbox and text
    
    //draw_self();
    
    if scroll_timer_sad = true{
        scroll_timer = 0.13;
    }
    
    if scroll_timer_slow = true{
        scroll_timer = 0.25;
    }
    
    if scroll_timer_regular = true{
        scroll_timer = 0.5;
    }
    
    if scroll_timer_fast = true{
        scroll_timer = 1.5;
    }
    
    if scroll_timer_scared = true{
        scroll_timer = 5;
    }
    
    ///drawing background of textbox
    //draw_rectangle_colour(mx2 - 200, my2 - 120, mx2 - 186 + string_width(speak[num]), my2 + string_height(speak[num]), c_white, c_white, c_white, c_white, false);
    if global.Convo == true && convo == true{
            ///setting the depth of textbox
            depth =  -170;
            ///set up the option to do certain things per sentence
           
            ///checking wich sentence player is currently reading
            switch (num){
                case 1:{
               
                }
                break;
               
                case 2:{
               
                }
                break;
               
                case 3:{
               
                }
                break;
                case 4:{
               
                }
                break;
               
                case 5:{
               
                }
                break;
               
                case 6:{
               
                }
                break;
               
                case 7:{
               
                }
                break;
               
                case 8:{
               
                }
                break;
               
                case 9:{
               
                }
                break;
               
                case 10:{
               
                }
                break;
               
                case 11:{
               
                }
                break;
               
                case 12:{
               
                }
                break;
               
                case 13:{
               
                }
                break;
               
                case 14:{
               
                }
                break;
               
                case 15:{
               
                }
                break;
               
                case 16:{
               
                }
                break;
               
                case 17:{
               
                }
                break;
               
                case 18:{
               
                }
                break;
               
                case 19:{
               
                }
                break;
               
                case 20:{
               
                }
                break;
               
                case 21:{
               
                }
                break;
                           
                case 23:{
               
                }
                break;
               
                case 24:{
               
                }
                break;
               
                case 25:{
               
                }
                break;
               
            }
            ///end checking sentence
            draw_set_font(fnt_textbox_test);
            /// draw rounded rectangle chatbox
            //draw_roundrect_colour(mx2 - 0, my2 - 40, mx2 - 0 + string_width(speak[num]) + 10, my2  + string_height(speak[num])- 25,c_white, c_white, 0);
           
            ///bg filler
            //draw_rectangle_colour(mx2 - 0, my2 - 0, mx2 - 0 + string_width(speak[num]), my2 - 0 + string_height(speak[num]), c_white, c_white, c_white, c_white, false);
            ///bg outilner
            //draw_rectangle_colour(mx2 - 0, my2 - 0, mx2 - 0 + string_width(speak[num]), my2 - 0 + string_height(speak[num]), c_reg, c_reg, c_reg, c_reg, true);
           
            ///drawing text
            //draw_text(mx2 +5 , my2 -30, speak[num]);
            ///drawing highlight text
            //draw_text_colour(mx2 +5, my2 -30, string_copy(speak[num], 0, scroll_text), c_reg, c_reg, c_reg, c_reg, 1);
           
            /// drawing the "next" button
            if scroll_text >= string_length(speak[num]){
                    ///drawing sprite
                    //draw_sprite(spr_convo_proceed, 0, mx2 - 168 + string_widith(speak[num]), my2 - 107 + string_height(speak[num])/1.4);
                    seconds = 0;
                    count_up = false;
            }
           
           
           
           
           
           
           
            ///Testing scrollable Textbox
            draw_roundrect_colour(x, y, x+width, y+height, c_white, c_white, false);
           
            //Checking if the width has been broken
            if(string_width(str) > width - padding - padding)
            {
                //Remove the space and replace it with a line break
                speak[num] = string_delete(speak[num],last_space, 1);
                speak[num] = string_insert("#", speak[num], last_space);
                ds_list_add(start, last_space+1);
               
            }
           
            //Making sure its not the end of the speak[num]
            if(count < string_length(speak[num]))
            {
                //Set the last space variable
                if(string_char_at(speak[num], count) == " ")
                {
                    last_space = count;
                }
               
                count ++;
            }
           
            //Check if bottom box has been broken
            if (string_height(str) > height-padding)
            {
                line++;
            }
            // draw textbox
            ///draw_text(x+padding, y+padding, str);
            draw_text_colour(x+padding, y+padding, string_copy(speak[num], 0, scroll_text), c_reg, c_reg, c_reg, c_reg, 1);
            // Grabs the string
            str = string_copy(speak[num], ds_list_find_value(start,line),count-ds_list_find_value(start,line));
            /// End Testing Scrollable Textbox
           
           
           
           
           
           
           
           
           
            ///Drawing the scrolling text (highlighting text)
            if scroll_text < string_length(speak[num]){
                scroll_text += scroll_timer;
            }
           
            if count_up = true{
                seconds += 1 / room_speed;
            }
           
            if seconds >= scroll_timer * 1.31 && scroll_timer_sad = true{
                audio_play_sound(sound_test, 10, false);
                seconds = 0;
            }
           
            else if seconds >= scroll_timer * 0.6 && scroll_timer_slow = true{
                audio_play_sound(sound_test, 10, false);
                seconds = 0;
            }
           
            else if seconds >= scroll_timer * 0.15 && scroll_timer_regular = true{
                audio_play_sound(sound_test, 10, false);
                seconds = 0;
            }
           
            else if seconds >= scroll_timer * 0.027 && scroll_timer_fast = true{
                audio_play_sound(sound_test, 10, false);
                seconds = 0;
            }
           
            else if seconds >= scroll_timer * 0.001 && scroll_timer_scared = true{
                audio_play_sound(sound_test, 10, false);
                seconds = 0;
            }
           
            ///Seeing if player is trying to proceed with convo
            if keyboard_check_pressed(ord(next_button)){
                count_up = true;
                ///see if text is still scrolling
                if scroll_text < string_length(speak[num]){
                    scroll_text = string_length(speak[num]);
                }
                else{
                    ///proceeding to next sentence or part of convo
                    if num < num_max{
                        num += 1;
                        scroll_text = 0;
                    }
                    /// checking if there is more to this convo and if player has reached breaking point
                    else if convo_part < convo_part_max{
                        convo_part += 1;
                       
                        ///creating a break point and/or proceeding to the next part of the convo
                        switch (convo_part){
                            case 2:{
                                num = 1;
                                num_max = 3;
                                convo_part = 1;
                                scroll_text = 0;
                                convo = false;
                                global.Convo = false;
                                convo_part -= 1;
                            }
                            break;
                           
                            case 3:{
                           
                            }
                            break;
                            case 4:{
                           
                            }
                            break;
                           
                            case 5:{
                           
                            }
                            break;
                           
                            case 6:{
                           
                            }
                            break;
                           
                            case 7:{
                           
                            }
                            break;
                           
                            case 8:{
                           
                            }
                            break;
                           
                            case 9:{
                           
                            }
                            break;
                           
                            case 10:{
                           
                            }
                            break;
                           
                            case 11:{
                           
                            }
                            break;
                           
                            case 12:{
                           
                            }
                            break;
                           
                            case 13:{
                           
                            }
                            break;
                           
                            case 14:{
                           
                            }
                            break;
                           
                            case 15:{
                           
                            }
                            break;
                           
                            case 16:{
                           
                            }
                            break;
                           
                            case 17:{
                           
                            }
                            break;
                           
                            case 18:{
                           
                            }
                            break;
                           
                            case 19:{
                           
                            }
                            break;
                           
                            case 20:{
                           
                            }
                            break;
                           
                            case 21:{
                           
                            }
                            break;
                           
                            case 23:{
                           
                            }
                            break;
                           
                            case 24:{
                           
                            }
                            break;
                           
                            case 25:{
                           
                            }
                            break;
                           
                            case 26:{
                           
                            }
                            break;
                           
                            case 27:{
                           
                            }
                            break;
                           
                            case 28:{
                           
                            }
                            break;
                           
                            case 29:{
                           
                            }
                            break;
                           
                            case 30:{
                           
                            }
                            break;
                           
                            case 31:{
                           
                            }
                            break;
                           
                            case 32:{
                           
                            }
                            break;
                           
                            case 33:{
                           
                            }
                            break;
                           
                            case 34:{
                           
                            }
                            break;
                           
                            case 35:{
                           
                            }
                            break;
                           
                            case 36:{
                           
                            }
                            break;
                           
                            case 37:{
                           
                            }
                            break;
                           
                            case 38:{
                           
                            }
                            break;
                           
                            case 39:{
                           
                            }
                            break;
                           
                            case 40:{
                           
                            }
                            break;
                           
                            case 41:{
                           
                            }
                            break;
                           
                            case 42:{
                           
                            }
                            break;
                           
                            case 43:{
                           
                            }
                            break;
                           
                            case 44:{
                           
                            }
                            break;
                           
                            case 45:{
                           
                            }
                            break;
                           
                            case 46:{
                           
                            }
                            break;
                           
                            case 47:{
                           
                            }
                            break;
                           
                            case 48:{
                           
                            }
                            break;
                           
                            case 49:{
                           
                            }
                            break;
                           
                            case 50:{
                           
                            }
                            break;
                    }/// endinf of checking wich part of convoi player is moving to
                }/// ending of checking current convo convo part and if there is more to current convo
                else if hidden_event == true{
                    ///increasing the counter used to tell game if player has met condition
                    //hidden_event_count += 1;
               
                    ///Checking if a condition is need and if it has been met
                    if hidden_event_count < hidden_event_max{
                        ///activate hidden event [below]
                       
                    }
                } /// end proceeding of next sentence
               
                else{
                    ///reset the whole convo or start the convo from a fixed position
                    num = 1;
                    num_max = 3;
                    convo_part = 1;
                    scroll_text = 0;
                    convo = false;
                    global.Convo = false;
                    exit;
                   
                }
            } ///end of player pressing the "next" button
        } ///end of convo being activated
    }
    else{
    ///checking if player is within talk range
            ///he is in talk range
        if collision_circle(mx2, my2, trange, c_obj, false, true){
            /// checking if player is trying to activate convo
            if keyboard_check_pressed(ord(talk_button)){
                global.Convo = true;
                convo= true;
                count_up = true;
                }
            }
    }
    
    
    You can see its much Bigger because I tinkered a little bit and altered a little bit to fit the scope of my project. The part that I added the scrollable textbox was really getting on my nerves because I dont really can get it to work properly, Im not quite sure why. Do you know how to fix this? Or even a better way to do the scrollable textbox in your engine?
     
    Xskode likes this.
  14. Xskode

    Xskode Member

    Joined:
    Jun 21, 2016
    Posts:
    55
    yes, if you want it to be a fix box size go into the draw event and remove the text functions from the x1, y1, x2, y2 positions. and replace them with the value you need.

    this is what you have

    draw_set_font(fnt_textbox_test);
    /// draw rounded rectangle chatbox
    //draw_roundrect_colour(mx2 - 0, my2 - 40, mx2 - 0 + string_width(speak[num]) + 10, my2 + string_height(speak[num])- 25,c_white, c_white, 0);

    ///bg filler
    //draw_rectangle_colour(mx2 - 0, my2 - 0, mx2 - 0 + string_width(speak[num]), my2 - 0 + string_height(speak[num]), c_white, c_white, c_white, c_white, false);
    ///bg outilner
    //draw_rectangle_colour(mx2 - 0, my2 - 0, mx2 - 0 + string_width(speak[num]), my2 - 0 + string_height(speak[num]), c_reg, c_reg, c_reg, c_reg, true);



    this is what you need (replace the numbers with the size you want, in the example the box will be a fix size of 500px in the center (Xaxis) and bottom (Yaxis) of a 1920x1080 view/room.)

    draw_set_font(fnt_textbox_test);
    /// draw rounded rectangle chatbox
    //draw_roundrect_colour( 710, 700, 1210, 1060,c_white, c_white, 0);

    ///bg filler
    //draw_rectangle_colour( 710, 700, 1210, 1060, c_white, c_white, c_white, c_white, false);
    ///bg outilner
    //draw_rectangle_colour( 710, 700, 1210, 1060, c_reg, c_reg, c_reg, c_reg, true);


    Clarity:
    so what I did is remove the code that makes the box change based on the length of the sentence. and replaced the code with a number value that I needed.
    as long as you remove that code (that makes box size change based on text's length) then the textbox will remain scrollable while being fixed. [[[ you can also replace the code with a variable if you like) ]]]
    this should help. but let me know if it does!
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice