In this chapter, we will learn about text output. We will look deeper into how fonts are created and stored and analyze the possible problems of AndEngine's way of displaying text characters. We will also learn how to create multilingual games and how to localize them.
We will see how to put text on a screen utilizing a heads-up display (HUD) in order to display the score of the game. Alternative ways of displaying text messages will also be discussed.
Finally, we will cover the basics of Android and AndEngine logging and debugging output.
A font is a file that defines the characters and sometimes special glyphs and symbols that can be printed on the screen. Fonts are typically defined as vectors. Because AndEngine and the OpenGL library in general don't work with vectors, we must first create a raster or bitmap font. We can imagine it as printing the entire alphabet with special characters using a font of our choice on an image and cutting out the letters. Afterwards, we create words using these cut-outs.
The following code shows how we load the font in the ResourceManager
class:
//font public Font font; public void loadFont() { font = FontFactory.createStroke(activity.getFontManager(), activity.getTextureManager(), 256, 256, Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD), 50, true, Color.WHITE_ABGR_PACKED_INT, 2, Color.BLACK_ABGR_PACKED_INT); font.load(); }
The first parameter passed is the FontManager
class. It's an AndEngine class that takes care of managing the fonts. The second parameter is the TextureManager
class. We pass it in because, as we will see later in this chapter, the font is basically a texture onto which we print letters.
The third and fourth parameters are the font texture width and height. The texture used is a minimal texture that can hold the entire English alphabet using the given font and size. We are going to see how the size of the texture can lead to common problems with fonts in AndEngine.
The fifth parameter is the font used. In this example, we are using a built-in font that is available on every Android device. However, it can actually differ in size a little on different Android versions. The sixth parameter, 50
, is the size of the font.
The next parameter tells AndEngine to use anti-aliasing to smoothen the edges of the text. It is followed by the eighth parameter, the font color. In our case, we will use white.
The last two parameters define a stroke around each letter as a two-pixels-wide black line.
When this code is called, the texture for the font is prepared. The font
object is ready to be used for outputting text. However, the font texture is empty at this moment. How is that possible? Simply because AndEngine loads the letters and puts them onto the texture only when they are needed for the first time. This is called
lazy loading.
We can force AndEngine to load all letters that we are going to use by calling the font.prepareLetters()
method.
Because AndEngine works with its own surface view, it can't simply output text as regular Android apps do. It must draw the text using small sprites. Each letter is in fact a sprite on its own. They are assembled into words by the Text
class.
Let's see what happens when we load the Latin alphabet. We start with all uppercase letters and some special characters. The following assignment can be added to the loadFont()
method in the ResourceManager
class:
font.prepareLetters("01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ.,!?".toCharArray());
We are using the toCharArray()
method because the prepareLetters()
method expects an array of characters.
You can opt to render only the characters that you are really going to use. Also, you can call the method with a sentence. Any repeating characters will be rendered only once and a space is not rendered at all. For example, in the sentence in the following line of code, only one E
will be rendered on the texture:
font.prepareLetters("GAME OVER!".toCharArray());
The final texture will look something like the following screenshot. Note that the texture is 256 pixels wide and 256 pixels tall. Each character is defined as a texture region in this texture.
A texture 256 x 256 pixels large can fit all numbers, all uppercase Latin alphabet letters, a comma, a period, an exclamation mark, and a question mark.
There are a few prerequisites for using special characters and international alphabets. First, the font used must contain them. The Android system font contains most of the UTF characters. However, some custom fonts don't. Second, AndEngine treats all letters as sprites; boxed entities, written from left to right. Any other writing systems that compile the words in a different way are not supported.
All this is very important to take into account when localizing games to other languages. Let's discuss what happens when using different international alphabets.
Most of the European language alphabets contain characters with a diacritic. They are rendered just fine, but they usually take more space. They must be rendered as separate characters and also the characters are usually taller.
First, we preload some of the characters to the texture map as follows:
font.prepareLetters("01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ ÁÉ".toCharArray());
The result is shown in the following screenshot:
The letters with diacritic take more space vertically. AndEngine will take care of the right positioning. Both top and bottom diacritics are rendered correctly.
Also notice that the width of each letter is different. The two new letters are the same width as the four punctuation marks combined.
Generally, writing systems that contain separate characters can be rendered.
The Korean alphabet, Hangul, is in fact a syllabary. Each character is constructed from vowel and consonant parts. To render Hangul in AndEngine, you have to prepare each combination separately. This can make the texture pretty big, but it still works.
The same is true for the Japanese alphabet. Each character of both hiragana and katakana (Japanese syllabic writing system) must be rendered separately, even the characters with Japanese diacritic dakuten (double dot or circle). This can be changed by overriding the Text
class and adding a special rule. But, this override is not implemented in AndEngine itself.
Finally, Chinese characters and Japanese Kanji (adopted Chinese characters) can be rendered easily. But, there are many of them. A larger texture might be needed.
Let's change the code to include the characters we would like to render. This can be done as follows:
font.prepareLetters("한글中文ひらがなカタカナ".toCharArray());
The following screenshot shows these Korean, Chinese, and Japanese characters rendered on to a texture:
If you can read Japanese, maybe you have noticed that the katakana part is composed only of ka, ta, and na, and one ka is missing. Each character is rendered only once, therefore the character ka is rendered only once.
AndEngine has a problem rendering other writing systems. For example, Thai script, Arabic script, or the script used to write the Hindi language can't be rendered correctly. It is possible to implement a custom rendering, but it would take quite a lot of work.
Let's try to prepare some Hindi, Thai, and Arabic alphabet with this code:
The following screenshot shows the result. Notice that there are some extra characters rendered separately and in general, it doesn't look like the text in the preceding line of code. This is due to the fact that some writing systems work very differently from the Latin alphabet, and AndEngine doesn't support them at all.
18.222.184.200