Today's coffee-break tutorial covers a great effect that is useful in a wide variety of situations. Making a dialogue object that has lines of text that appear a letter at a time, just like it was being written on a typewriter! How to make an effect like this is a recurrent question we see come up on the forums and other social platforms, and while there are a number of great assets out there that will permit you to do this. We thought we would show you how this can be done in the simplest form, so you can learn and have base to build your own text systems.
NOTE: This tutorial is for people that use DnD. If you prefer to use GML to make your games, we have a companion article for you here.
For this tutorial, you will need to create a new project in GameMaker Studio 2 as we'll be starting from scratch. In this project you should add a new font asset and give it a name (in this tutorial we'll be calling it simply
fnt_dialog), and then add a new object asset and name it
We'll be adding all our actions into the dialog object and the idea is that we'll be creating an array of text, where each item in the array is a complete sentence or paragraph of text, and then we'll be taking that text and drawing only a section of it each step, advancing the section to show a new letter little by little to create the typewriter effect. So, let's get started...
THE STRING_WRAP FUNCTION
Before we add any actions into our dialog object, we need to first define a function that we'll need to deal with wrapping text that is too long for the space we want to draw it in. Now, GameMaker Studio 2 has a GML function
draw_text_ext that can be used to automatically wrap text when it overflows a given length, and in many cases that will be perfectly fine to use. However, since we will be drawing our text a letter at a time, this function causes an issue where words will start to appear on one line, then "jump" to the next as the GML function detects that they are now longer than the maximum width. You can see this happening in the following GIF:
To prevent this from happening, we are going to take our input string then run it through a function that will add in the required line breaks based on the position of spaces in the text. This will mean that the string will be pre-formatted to go to a new line before it's even drawn.
You should make a new Script asset for this and while you can name it anything you wish, for the sake of this tutorial, we'll call it the same as the function it's going to contain:
string_wrap. In the script you'll see that there is already a Declare A New Function action present, so fill it out as shown in the image below, and add an Execute Code action to it:
The code we'll be using is shown below, and you should simply copy and paste it directly into the Execute Code action:
var _text_wrapped = "";
var _space = -1;
var _char_pos = 1;
while (string_length(_text) >= _char_pos)
if (string_width(string_copy(_text, 1, _char_pos)) > _width)
if (_space != -1)
_text_wrapped += string_copy(_text, 1, _space) + "\n";
_text = string_copy(_text, _space + 1, string_length(_text) - (_space));
_char_pos = 1;
_space = -1;
if (string_char_at(_text,_char_pos) == " ")
_space = _char_pos;
_char_pos += 1;
if (string_length(_text) > 0)
_text_wrapped += _text;
All this script is doing is looping through the given string a letter at a time and checking to see if the length of the string after each letter is added to it overflows the permitted text width, while also storing the position of the last space found between words in a variable. If the text does overflow the given width, then the function adds a line break (
"\n") into the text at the last space, then continues on, and it will do this for the entire length of the given text, adding as many line breaks as required.
THE CREATE EVENT
With that done, we can turn our attention to the dialog object and actually start to code our typewriter effect. To start with we need to add a Create Event to set up some variables that our object will need. We'll need quite a few variables to control things, so we've broken it into blocks of variables to make it easier, so add a Create Event to the object now, and then add this first block:
This first block defines an array which is what we'll use to contain each of our lines of dialogue. Here we're adding in two lines, but you can add more as you wish, just make sure that you increment the array position for each line. Now add the following:
This next block initialises all the controller variables that will be required to draw our text using the typewriter effect. These variables are as follows:
text_current: this will be used to tell GameMaker what the current text array position to use for the text.
text_last: this will be used to tell GameMaker what the last array position is, in this case 1 as we have 2 positions - 0 and 1 - in our array. For an array with position 0, 1, 2, and 3, then this variable would be set to 3.
text_width: this is the maximum width that we want the text to be drawn before it wraps to a new line
text_x: the X position where we want to draw the text in the room
text_y: the Y position where we want to draw the text in the room
The final block of variables to add looks like this:
These two variables will control the current last character of the text being drawn, and the timing of when each character is drawn. By changing the variable
char_speedyou can change how fast or slow the text appears on the screen.
The last thing to do in our Create Event is to call the function we created earlier on the first line of text we'll be drawing so that it wraps correctly within the given width:
KEY PRESS "SPACE" EVENT
Most typewriter effects permit you to skip the effect in some way, and so we'll be adding this into our own example. We want the skip effect to work in two different ways:
If the current line hasn't finished being drawn, then pressing skip will draw the whole line right to the end instantly
If the current line has finished being drawn, then pressing skip will go to the next line and start drawing that
We'll do this using the Space key on the keyboard, but you can use any input method you want as the actions we'll show will be the same. So, add a Keyboard Pressed - Space event to the dialog object now. First, we'll check the length of the whole string being drawn against the current position of what is actually being drawn, like this:
All this does is set the current last character being drawn to the last character in the whole string, so the whole string will instantly be displayed. If the whole string is already being displayed, then we need to use the
elseand add into that the following:
Here we advance the variable that tells GameMaker which array position to get the text from, and then we check to see if we've advanced outside of the size of the array. If we have, then we restart the room, but that's just for this tutorial. Normally you'd then destroy the dialog object or have your game perform some action here. If there is still more text in the array, then we call our
string_wrapfunction to add line breaks to the next line to be displayed and reset the current last character to the start of the string ready to display it letter-by-letter again.
THE DRAW EVENT
The draw event is probably the simplest of all to set up and we'll start by setting how we want the text to be displayed by choosing a font, position and colour. Add a Draw Event now and give it these actions:
With that done, it's time to actually draw our dialogue text! First, we need to check the current last character of the text being drawn, and if it's not the last character of the whole text, advance it by the speed that we set in the create event:
To draw the text, we simply use the
string_copy() function to copy the section of the total text from the beginning to the current last character and then draw that, like this (under the "If", not as part of it):
You can add the dialog object to a room now and run the game and the results should be something like this:
With this, you now have a dialog object that you can use at any time in a game! How do you ask? Well, all you need to do is set the the different variables as the object is created. For example, in our test project, you can create a controller object and give it a key or mouse event, and in that event, you can add something like this:
Here we are creating a dialog instance and then using the Apply to... action to set the text, number of lines, and the width and position of the dialog object. You could even create a new function that does all this for you using these actions as a template.
That's it for this Coffee-break Tutorial, and we hope it's been useful to you!