Are you making a story-driven game like an RPG or interactive novel?
Having text show up one character at a time is common in those types of games and makes it feel like the characters are talking!
Maybe you've come across tutorials for doing this that are no longer up to date or don't work with Phaser 3?
Well, you are in luck!
In this article, we will show you how to create a typewriter effect for Text
and BitmapText
GameObjects for Phaser 3.
Scene Set-Up
All our example code is going to be within the context of this demo Scene:
|
|
We'll be using modern JavaScript and a project based on the phaser3-parcel-template.
If you are not familiar with using modern JavaScript with Phaser 3 then we have a free book to help you get started!
Learn to make an Infinite Jumper in Phaser 3 with modern JavaScript!
Drop your email into the box below to get this free 60+ page book and join our newsletter.
Typewriter for Text
The core concept behind this effect is to add 1 character from a string to a Text
object at a consistent interval until all the characters are added.
Let's start by creating a Text
object:
|
|
We use a class property called label
to store the created Text
GameObject.
Notice that we are passing in an empty string to start.
Next, let's make a method that will take a string and display each character one at a time:
|
|
We use this.time.addEvent
to have a function called every 200 milliseconds that repeats length - 1
times.
The length
variable is the number of characters from the given text
string.
This will let us append 1 character from text
to this.label.text
each time the function is called.
The variable i
is used to keep track of which character to append to this.label.text
each time the function is called.
Call this method from create()
to see the typewriter effect in action:
|
|
Typewriter for Text that Wraps
In some cases, the above implementation will work fine for text that wraps but there can be times when a word is getting typed out and then suddenly wraps once it reaches the bounds of the text box.
A better approach is to go to a new line if a word being typed out is going to be wrapped.
Let's do that in a new method called typewriteTextWrapped(text)
:
|
|
Notice that this method reuses typewriteText()
after it generates a string with line breaks in the appropriate places.
We start by calling the getWrappedText()
method on this.label
to get each wrapped line as an entry in a list called lines
.
Then we simply join the array using a line break (\n
) to create a string that wraps properly when given to this.typewriteText(wrappedText)
.
Try it out by setting a width on this.label
and then calling this.typewriteTextWrapped()
:
|
|
In practice, you'll likely always want to use the version that wraps so you can merge these two methods into one.
Typewriter for BitmapText
The core concepts will be the same for BitmapText
but the specifics will be a little bit different from Text
We will be using some properties that are not officially documented but is used internally by Phaser.
Let's start by loading a bitmap font:
|
|
We used bmGlyph for Mac to generate the font assets and chose the “Sparrow / Starling” publish option.
There's also BMFont for Windows, Glyph Designer for Mac, and a web-based one called Littera.
Next, let's create a BitmapText
GameObject:
|
|
We added a class property called bitmapLabel
and then set it to a BitmapText
instance that uses the font we loaded.
Then we call setMaxWidth(500)
to designate a width for wrapping.
To perform the typewriter effect logic, let's create a typewriteBitmapText()
method:
|
|
The second half of this method should be familiar as it is virtually identical to the typewriteText()
method we created earlier.
The main difference is the first 4 lines where we start by seting the text with this.bitmapLabel.setText(text)
and then use getTextBounds(false)
to get the information we need.
You can log bounds
to the console to see what properties it has. The official docs for BitmapTextSize
has just 2 properties but you'll see that there's more.
The one that interests us is wrappedText
as it contains a string with line breaks placed at the appropriate places.
Because it is not officially documented, we store it into a local wrappedText
variable using key access and the logical OR operator on line 10.
This means the local wrappedText
variable will be set to text
if bounds.wrappedText
does not exist. We access the property as a key to avoid VS Code showing us an error but that is optional.
Try it out by calling the method in create()
:
|
|
One thing to note is that we are setting and then clearing out the text on lines 7 and 12 in typewriteBitmapText()
It would be better if we did not have to do this but we did not see another way to get the necessary wrapped text information.
Let us know in the comments below if you know of another way to do this!
Next Steps
You now know the core concept for creating a typewriter effect for Text
and BitmapText
. You can apply the same concepts for DynamicBitmapText
!
Feel free to adjust the delay
property from 200
milliseconds to something slower or faster depending on your game.
Be sure to sign up for our newsletter so you don't miss any future Phaser 3 game development tips and techniques!
Drop your email into the box below.
Don't miss any Phaser 3 game development content
Subscribers get exclusive tips & techniques not found on the blog!
Join our newsletter. It's free. We don't spam. Spamming is for jerks.