GML [Textbox System] Help changing text color mid string / shake effects?

GonerBits

Member
(I'm a total beginner to this, and this is my first time posting to here, so sorry if the formatting / code is kind of messy... I don't know what i'm doing haha)

I'm trying to make a text box system that allows for shaking text and changing text colors (preferably in a gradient) kind of like how you see in some RPGs.

I've been trying to study the ways a lot of people do this kind of effect and here's what I've come up with so far...

Code:
//CREATE EVENT
//Text pages
text[0] = "This is page 0!"
text[1] = "Annd this is page 1..."
page = 0
page_total = array_length_1d(text)
//Speed of drawing each character
charspd = 12
char = 1
alarm[0] = charspd
//Where to draw text
text_xstart = 40
text_ystart = 40
text_x = text_xstart
text_y = text_ystart
//Gradient colors
color1 = c_white
color2 = c_white
//Used for shaking
intensity = 0;
Code:
//DRAW GUI EVENT
draw_set_font(font)
//Set up shaking
shake_x = random_range(-intensity,intensity)
shake_y = random_range(-intensity,intensity)
//Get one letter
currletter = string_char_at(text[page],char)
nextletter = string_char_at(text[page],char+1)
char_width = string_width(currletter)
//Draw one letter
draw_text_color(text_x+shake_x,text_y+shake_y,currletter,color1,color1,color2,color2,1)
Code:
//ALARM 0
if char < string_length(text[page]) {
   
    //Play sound
    if currletter != " " {
        audio_play_sound(snd_text,5,false)
    }
   
    //Change color when the tag comes up
    if nextletter = "&" {
        text[page] = string_delete(text[page],char,1)
       
        //(Example of changing text properties... making it blue and shaky, changing the speed)
        color2 = c_blue
        intensity = 1
        charspd = 20

    }
   
    //Go to next letter / position
    char ++
    text_x += char_width
   
    alarm[0] = charspd
}
Code:
//Key press - Z
//Go to next page
if page < page_total {
    page += 1
    char = 1;
    text_x = text_xstart
    alarm[0] = charspd
}
In order to change colors / make each letter shake individually, I know I have to draw each letter as a separate string... My problem here is that every time it draws a letter, the one before it disappears. I need to find a way to keep every previous letter on the screen without just using string_copy and making it into one string, but I'm not sure how...

It seems almost like I might need a "draw_text_color" function for every single letter of a string, but I'm not sure how I would implement something like that exactly.

Then in addition it needs to make sure each string stores its original attributes (color, shakiness etc) so that when I change the color only the letters AFTER the tag change, rather than all the letters at once.

Any help would be greatly appreciated...
 
For me, I'd create a script that manages every single character in the current dialogue sequence by letting each of them be drawn by multiple character objects and let them handle the character's behavior, or create a loop in the Draw GUI event that draws every single (initialized) letter with specified inputs and conditions which were stored in memory.

The method I used might be a good practice, but it's a pain in the heck to think of performance issues. I'm not sure of that since I hadn't checked the cost of it, I sort of added it and called it a day. The second one might be a good concept. Here's something you can take a look at. You can play with it until when you figure it out, or you can ask us again if you need more help. (i recommend messing with it first)

Code:
//Draw GUI (test it if you wish, you can figure out ways to do it after this!)
//All of these resets after the event
var randx, randy;
var textx = 40;
var texty = 40;
var hadd = 0; //Adds up every loop
var curcolor = c_white;
var tempchar = "a";

draw_set_font(-1);

repeat(10) { //Loop 10 times, draws 10 characters in one draw event.

   //shaky shaky
   randx = random_range(-1,1);
   randy = random_range(-1,1);

   //Changes color once certain criteria is met
   if(hadd>=50) curcolor = c_yellow;

   //now we draw
   draw_text_color(textx+randx+hadd, texty+randy, tempchar,curcolor,curcolor,curcolor,curcolor,1);

   hadd+=10;
}

//end
 
Last edited:
I'd have to think on this, but there are hidden characters in text editors and you can use them in strings. As an example: " " or " " (just to make it easier to see that there is multiple spaces there) will actually be treated as having those gaps when drawn or accessed.

To do horizontal gaps I would just edit the string being shown:

1) Find the word to show that will have the different colour, and the altered spacing
2) Get it's start point in the string, and add one to that position (so it's after the first letter)
3) Do a random choice for what length the space is, and add however many spaces that is to the string - plus the starting point.
4) Repeat step 2 to 4

I'll call the word "booooooooom!" for this example.

In terms of code (off of the top of my head) this would be something like:

Either

A) You know what point in the lines of dialogue you want the text to be altered, and refer to that in a loop when drawing it

Code:
for (a = 0: a < whatever; a++)
{
if a == line to edit
{
do altered text (something like down below in B)
}
else
{
draw normal text
}
}
B) You read the string as it is being drawn, and find the word

draw event:
Code:
is_file = file_text_open_read(whatever); // This is taken from a project doing something different, so I'm just leaving it here to show a file being opened

text = file_text_readln(is_file); // ditto ^^^^^^ This would only read the first line, and was part of a while loop that read the whole file. But you only want one line at time (?) so it would be different as to how you handle this
is_word = "booooooooom!";
is_length = string_length(is_word)
var_pos = string_pos(is_word, text);
if var_pos != 0
{
start_pos = var_pos + 1;

// get the part of string before the word
first_part = string_copy(text, 1, var_pos - 1);

// get the part of string after the word
third_part = string_copy(text, start_pos + is_length, string_length(text));

repeat (is_length)
{
add_to_pos = irandom_range (1, 10); // 10 is an arbitrary number here
repeat (add_to_pos)
{
str2 = string_insert(" ", is_word, start_pos);
is_word = str2;
}
start_pos +=  (add_to_pos + 1);
}
is_length = string_length(is_word) // final length after adding in spaces - can be used to figure out where third part should be drawn after second part (the word)

// set normal colour
draw text (first part)

// set new colour
draw text (is_word)

// set normal colour
draw text (third part)
}
else
{
draw text normally
}

file_text_close(is_file);
If I've figured that correctly it should be splitting up the parts of the text into three. Before the word, the word, and after the word. The word has had random spaces added to it after each letter.

You'd still need to figure out where to draw onscreen part two (the word) and then have part three, but that is why I included finding the length of the word after it has been edited.

As I said - this is off the top of my head, so it might be wrong or need tweaking. But, in theory, the only problem I would expect is that you'd want to control how often this is altered. Because it will be doing it every step, and the word will be jumping around like crazy if you don't :)

Having said that I can think of a way that's fairly easy to stop that happening (store "is_word" in a permanent variable after it's been altered, and then draw that instead. Only update it after x amount of time)

Hopefully this isn't all a load of rubbish, and has given you an idea of how you could do this in a way that's relatively straightforward. If you need any help understanding what it's doing, feel free to ask :)
 

GonerBits

Member
Thank you for responding!

This works great! I've tweaked it so that I can draw an entire sentence, one letter at a time, play sounds and everything... now I'm just trying to make it so that the tags in the string itself can change colors / shakiness, etc.

I've made it so it can detect the tag, but I still have one tiny problem...

With this code, it either skips over the tag correctly but doesn't change the effect, or it changes the effect but the tag is still visible -- depending on if I add the code or not.

Here's the example:

Code:
//DRAW GUI

var randx, randy;
var textx = 40;
var texty = 40;
var hadd = 0;
var curcolor = c_white;
var curchar = 1
var intensity = 0;
draw_set_font(fnt_realms);
realtext = string_copy(text[page],1,99)
repeat(repeatnumb) {
 
    var curletter = string_copy(text[page],curchar,1)
    var nextletter = string_copy(text[page],curchar+1,2)
 
   randx = random_range(-intensity,intensity);
   randy = random_range(-intensity,intensity);
 
   if(nextletter = "&b") {
     
       text[page] = string_delete(text[page],curchar+1,2) // THIS LINE - With this line, it doesn't draw the tag but the effects don't work-- without it, the effects work but the tag still displays...
       intensity = 1
       curcolor = c_blue
     
   }
 
   draw_text_color(textx+randx+hadd, texty+randy, curletter,curcolor,curcolor,c_white,c_white,1);
   curchar += 1
   hadd+=string_width(curletter);
}
Do you know if there's a way to make it so it still deletes the tag from the string while keeping the effects..?

Again, thank you for taking the time to look into this.



Edit: In case you need the other code, here it is...

Code:
//Create
text[0] = "Here's the &btag!"
text[1] = "Yay...."
text[2] = "This isn't &bworking."
page = 0
char = 1
charspd = 6
realcharspd = charspd
alarm[0] = charspd
repeatnumb = 1
Code:
//Alarm 0
if char < string_length(text[page]) {
audio_play_sound(snd_cursor,5,false)
char += 1
repeatnumb += 1
alarm[0] = realcharspd
}
Code:
//Key Pressed - Z
if char >= string_length(text[page]) {
    page += 1
    char = 1
    curchar = 1
    repeatnumb = 1
    alarm[0] = charspd
}
if page = array_length_1d(text) {
    instance_destroy()
}
Code:
//Step
if keyboard_check(ord("X")) {
    realcharspd = charspd / 4
} else realcharspd = charspd

EDIT: Nevermind! I've been fiddling around and I found a way to do it! Thank you so much!
 
Last edited:
Top