While you may be most familiar with TrueType Fonts (TTF), they are not the best supported approach when it comes to font rendering in games; this also applies to the Libgdx environment. Rendering text from a TTF is a costly process because it involves rasterizing the vector representation of the font onto a texture.
Instead, TTF files are baked into textures or bitmap fonts using an offline tool, such as Hiero, as you will see later in this recipe. This way, the graphics system only needs to load a texture and the location of each contained character. Rendering text becomes a lot simpler: rendering multiple regions using additional logic for correct character positioning. Don't worry, Libgdx does all of this for us!
In this recipe, we will create bitmap fonts from TTF files using Hiero, a tool distributed with the Libgdx package. Then, we will use the result to render text in various ways within a Libgdx application.
To get a hold of Hiero, get the latest Libgdx package and unzip it somewhere in your hard drive (http://libgdx.badlogicgames.com/releases).
For our recipe, we will use the data/fonts/play.fnt
file to render text on the screen. We will also be using the samples
projects, as usual.
We are going to subdivide the process for this recipe in two steps. First, we will generate our font texture with Hiero, and then, we will cover the rendering process with Libgdx.
Perform the following steps to run Hiero and generate a bitmap font texture:
java -cp gdx.jar;gdx-natives.jar;gdx-backend-lwjgl.jar;gdx-backend-lwjgl-natives.jar;extensionsgdx-toolsgdx-tools.jar com.badlogic.gdx.tools.hiero.Hiero
If you use either Linux or Mac, you need to replace backslashes with forward slashes:
java -cp gdx.jar:gdx-natives.jar:gdx-backend-lwjgl.jar:gdx-backend-lwjgl-natives.jar:extensions/gdx-tools/gdx-tools.jar com.badlogic.gdx.tools.hiero.Hiero
Fantastic! You can now generate bitmap fonts.
The code for this example is inside the BitmapFontSample
class. First, we add our classic Viewport
, OrthographicCamera
, and SpriteBatch
classes. This time, we will also need BitmapFont
, the class that handles the loading and rendering of texture-based fonts.
The font is loaded inside the create()
method, simply by passing in the data/fonts/play.fnt
file:
font = new BitmapFont(Gdx.files.internal("data/fonts/play.fnt"));
By default, a bitmap font will allocate and own its texture, so you need to dispose of it appropriately. We do so in the dispose()
method:
font.dispose();
The meaty part takes place inside the render()
method, between the calls to begin()
and end()
. The most straightforward way to render text is through the draw()
function in BitmapFont
. It takes SpriteBatch
, the string you want to render, and a pair of (x, y) coordinates:
font.draw(batch, "This is a one line string", 20.0f, VIRTUAL_HEIGHT - 50.0f);
You can also draw several lines in one go using the drawMultiline()
method. It takes the same parameters as draw()
, but it looks for line break characters,
:
font.drawMultiLine(batch, "This is a multiline string", 20.0f, VIRTUAL_HEIGHT - 150.0f);
Sometimes, you will have limited space to render your text and you do not want to insert line breaks manually because that could be a pain. It is possible to wrap your text so that it fits within a given width, through the drawWrapped()
method:
font.drawWrapped(batch, "[...]", 20.0f, VIRTUAL_HEIGHT - 400.0f, 900.0f);
While working with Hiero, we intentionally made our texture white so that we could change the rendered color programmatically. This can be achieved with the setColor()
function, but beware as it is a state-changing procedure, meaning that all subsequent draw calls will have this color applied:
font.setColor(Color.RED);
You can also change the color of a string within a single draw call using special markup:
[color-name]
: This sets the current color by name from a predefined list[#RRGGBBAA]
: This sets the color by a hexadecimal value; AA
defaults to 0xFF
[]
: This sets the current color to the previous one[[
: This escapes the [
characterTo enable this feature, you need to call the setMarkupEnabled(true)
method on the font reference. Here are a couple of examples of how to render a multicolor string:
font.draw(batch, "[PURPLE]This [BLUE]is [GREEN]a [YELLOW]cool [ORANGE]multicolor [RED]string", 0.0f, 0.0f); font.draw(batch, "[#ff00ff]This [#0000ff]is [#00ff00]a [#66ff00]cool [#ffff00]multicolor [#ff0000]string", 0.0f, 0.0f);
The BitmapFont
instances can also be scaled using the setScale()
method; keep in mind that this is also a state-changing operation:
font.setScale(1.5f);
The following screenshot illustrates the results of this sample. Now, you can add awesome text to your game!
Even though it makes life so much easier for us, BitmapFont
actually works in quite a simple way. It loads a font.fnt
file, which is nothing more than a plain text file pointing to a texture. The file contains information of where the characters are located inside the texture and additional font metrics. This data is used to render characters together in a way that makes sense and feels pleasant.
Here is an extract of data/arial-15.fnt
:
info face=Arial,Normal size=15 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=0 aa=1 padding=0,0,0,0 spacing=1,1 common lineHeight=17 base=14 scaleW=1024 scaleH=1024 pages=1 packed=0 page id=0 file=arial-15_00.png chars count=190 char id=33 x=957 y=12 width=1 height=11 xoffset=2 yoffset=3 xadvance=5 page=0 chnl=0
Fonts have a set of metrics associated with them; let's take a look at the basics:
The following diagram illustrates the main features of a font:
Libgdx lets you query metrics from a font using the following methods:
font.getAscent(); font.getDescent(); font.getCapHeight(); font.getLineHeight(); font.getSpaceWidth();
You can actually check how much space a piece of text will take on the screen with the given string, using the getBounds()
and TextBounds
objects it takes. A TextBounds
object only has two fields: width
and height
:
void getBounds(CharSequence str, TextBounds bounds);
Although Hiero will serve you well, you might want to take a look at a few alternatives:
You might want to consider packing the font texture with your other sprites in order to reduce the number of texture switches when rendering the scene.
18.117.98.250