Construct 2: Text typing and word wrap tutorial

27th October 2018

Construct 2 Tutorial

Everybody loves that RPG text-typing effect whereby your game's dialogue is spelled out in the textbox letter-by-letter rather than appearing all in one lump. However, this can cause conflicts with the word wrapping on your text object.

This is a mistake I see in a lot of indie games - the visual bug whereby text starts typing out across the box, but then the word-wrapping kicks in mid-word and causes the entire last word of the line to 'jump' down to the line below. It looks like this:

Terrible text typing bug
It's pretty gross - you'd never see that happen in Zelda or Final Fantasy, would you? A few years ago I posted a solution on the Construct 2 forums which has since been removed, but I have continued to get questions about it from time to time - so I thought I would take the time to write up a full explanation.

My solution assumes you will be using a SpriteFont rather than the plain Text plugin (which is horrible for games anyway, due to possible rendering and font discrepancies on the user's machine), and works by processing your text to automatically insert line breaks every x characters before it is rendered to the screen. It works best for monospaced fonts with consistent character widths.

The reason is that you will need to know how many characters to allow per line - the first step is to give your SpriteFont an instance variable named charsPerLine. This is where we will tell the game engine how long each line should be - for me, it was 39 characters. In my example, my SpriteFont is named MainSpritefont.

If your game doesn't use a monospaced font, and all the character widths are different, you can still use this method, but you'll need to work out how many characters is a good rule of thumb for your font - perhaps by counting the number of characters in a string containing a lot of M's and W's (usually the widest letters in most fonts). By calculating a worst-case scenario, you can come up with a good character limit.

My Construct 2 Typewriter Text With Word Wrap

The following system makes use of Rex's Text Typing behaviour, which is available here. Essentially, what my solution does is it splits your string into individual words and then reassembles it, checking each word and counting characters to see if it makes a given line too long.

First of all, you will need to create a Global Variable called textToProcess. This is where we will put the initial, unprocessed text.

This is the function:

Construct 2 text typing system
I'm going to go into detail and break down exactly how and why it works, but you can simply replicate this as-is to create the same effect in your game.

If you're interested to understand how the thing works... read on!

How does this function work?

First of all, there are three Local Variables - Assembler, charsToIgnore and whatIndex.

That having been set up, now we create the function, processNewLines(). This allows us to easily call this entire block of events during the game whenever we want to invoke the text-typing word wrap effect.

The While loop explained

The first sub-event of the function establishes a While loop that splits your string into individual words using tokencount(). A while loop is a programming concept that means that while a certain condition or set of conditions is true, the code will loop around again and again until it becomes not true.

Tokens are incredibly useful in Construct 2, and let you split a string into chunks by using any character you like as a divider. Therefore, tokencount(textToProcess," ") splits your string into tokens every time it encounters a space and then counts them - giving us a count of how many words are in your string.

For example, "This is an example, everybody!" gets split into "This", "is", "an", "example," "everybody!" and gets counted as five tokens. The While loop checks to see if the number of words is greater or equal to the whatIndex variable. Because whatIndex will be incremented every time the function checks a word, this whole While loop basically means: while the total number of words in the string is greater or equal to the index of the word we're on - for example, if there are nine words, and we're on word five, the While loop is upheld as true and the further sub-events are executed. If it is false, that means all of the words have been processed and the loop has ended.

Now we come to the next sub-event, with the most complicated-looking condition of them all:

len(Assembler)-charsToIgnore+len(tokenat(textToProcess,whatIndex," ")) ≤ MainSpritefont.charsPerLine

I promise it's not as scary as it looks! Let's break it down:

So, in plain English, this condition literally means: If the length of the string assembled so far, minus any characters on lines already processed, plus the character length of the current word in the string, is less than or equal to the character-per-line limit of the SpriteFont...

In even simpler wording, we're testing the character count of a given word in the string to see if we can add it to the current line without going over our character limit. That's all it does. Then, if this condition is true, the events simply add the word to the processed output in the Assembler and increment the whatIndex counter by 1 - allowing us to progress onto the next word and continue for another round of the While loop.

Still with me? It gets easier, I promise...

Next, we have an Else condition. This means that if the previous condition was not true, the system does these events instead. In this particular case, that equates to "the current word can not be added to the assembled string without going over the characters-per-line limit".

This is the part we've all been waiting for - the key thing we need this whole function to do. The system has identified that a line will become too long, and we need to insert a line break at the end of the Assembler to make the word wrap effect behave properly. This is done via the system expression newline.

Next, we need to tell our function that the characters of the line we've just completed should not be counted any more - that line is finished, and we can move on. To do this, we set the value of charsToIgnore to the current character count of Assembler via len(Assembler).

The rest of the actions triggered by the Else condition are identical to earlier, and simply start the process of building another line afresh.

After the While loop

Now we come to this condition:

tokencount(textToProcess," ") < whatIndex

This condition tests to see if we've processed all the words. When the word count of our initial textToProcess is less than the number of words the function has attempted to process, the entire operation is complete - every available word has been evaluated.

Now, we wrap everything up by doing the following:

Enjoy your typing text effect!

Now all you need to do to call this effect any time you want is to

  1. Put the text you want to type into the textToProcess variable, and

  2. Call the function processNewlines().

Your SpriteFont will now type out your message with correct word-wrapping! Hooray!

I hope this post has solved your Construct 2 textbox problems - if not, please feel free to approach me on Twitter! I promise I'll do my best to help!

More stuff to read...

My Twitter  My Instagram  My YouTube
Mike's signature