Applying text to a layer
Text is an important part of game development as it can be used to dynamically display point systems, tutorials, descriptions, and more. AndEngine also allows us to create text styles which suit individual game types better by specifying customized Font
objects. In this recipe, we're going to create a Text
object, which updates itself with the current system time as well as correct its position every time the length of the string grows or shrinks. This will prepare us for the use of Text
objects in cases where we need to display scores, time, and other non-specific dynamic string situations.
Getting ready…
Applying Text
objects to our Scene
object requires a working knowledge of AndEngine's font resources. Please perform the the recipe, Using AndEngine font resources in Chapter 1, Working with Entities, then proceed with the How to do it... section of this recipe. Refer to the class named ApplyingText
in the code bundle for this recipe's activity in code.
How to do it…
When applying Text
objects to our Scene
object, we are required to create a Font
object which will define the text's style, and create the Text
object itself. See the folllowing steps for the specific actions we must take in order to properly display a Text
object on our scene:
- The first step to creating any
Text
object is to prepare ourselves aFont
object. TheFont
object will act as the resource which defines the style of theText
object. Additionally, we need to prepare the letters that we plan for theText
object to display:mFont = FontFactory.create(mEngine.getFontManager(), mEngine.getTextureManager(), 256, 256, Typeface.create(Typeface.DEFAULT, Typeface.NORMAL), 32f, true, Color.WHITE); mFont.load(); /* * Prepare the mFont object for the most common characters used. This * will eliminate the need for the garbage collector to run when using a * letter/number that's never been used before */ mFont.prepareLetters("Time: 1234567890".toCharArray()); Once we've got our Font object created and ready for use, we can create the Text: /* Create the time Text object which will update itself as time passes */ Text mTimeText = new Text(0, timeTextHeight, mFont, TIME_STRING_PREFIX + TIME_FORMAT, MAX_CHARACTER_COUNT, mEngine.getVertexBufferObjectManager()) { // Overridden methods as seen in step 3... };
- If we're dealing with final strings which may never change, only the first two steps need to be covered. However, in this recipe we will need to override the
onManagedUpdate()
method of theText
entity in order to make adjustments to its string over time. In this case, we're updating the time value of the string after every second passed:int lastSecond = 0; @Override protected void onManagedUpdate(float pSecondsElapsed) { Calendar c = Calendar.getInstance(); /* * We will only obtain the second for now in order to verify * that it's time to update the Text's string */ final int second = c.get(Calendar.SECOND); /* * If the last update's second value is not equal to the * current... */ if (lastSecond != second) { /* Obtain the new hour and minute time values */ final int hour = c.get(Calendar.HOUR); final int minute = c.get(Calendar.MINUTE); /* also, update the latest second value */ lastSecond = second; /* Build a new string with the current time */ final String timeTextSuffix = hour + ":" + minute + ":" + second; /* Set the Text object's string to that of the new time */ this.setText(TIME_STRING_PREFIX + timeTextSuffix); /* * Since the width of the Text will change with every change * in second, we should realign the Text position to the * edge of the screen minus half the Text's width */ this.setX(WIDTH - this.getWidth() * 0.5f); } super.onManagedUpdate(pSecondsElapsed); } Finally, we can make color adjustments to the Text and then attach it to the Scene or another Entity: /* Change the color of the Text to blue */ mTimeText.setColor(0, 0, 1); /* Attach the Text object to the Scene */ mScene.attachChild(mTimeText);
How it works…
By this point, we should already have an understanding of how to create the Font
object as we had discussed it in the first chapter. If creating Font
objects is not yet understood, please visit the recipe, Using AndEngine font resources in Chapter 1, Working with Entities.
In the first step, we are simply creating a basic Font
object which will create a rather generic style for our Text
object. Once the Font
object has been created, we are preparing only the necessary characters that will be displayed throughout the life of the Text
object with the mFont.prepareLetters()
method. Doing so allows us to avoid garbage collector invocations within the Font
object. The values used in this recipe will obviously range from 0
to 9
as we are dealing with time, as well as the individual characters that make up the string, Time:
.
Once step one is completed, we can move onto step two where we create the Text
object. The Text
object requires that we specify its initial position on the screen in x and y coordinates, the Font
object to use as a style, the initial string to display, its maximum character count, and finally the vertex buffer object manager as needed by all Entity
objects. However, since we're dealing with a dynamically-updating String
value for this Text
object, which will require adjustments on the x axis, the parameters including the x coordinate as well as the initial string are not so important as they will be adjusted frequently during updates to the Text
object. The most important parameter is the maximum character count. Failing to keep the Text
object's maximum character count below that of the value specified within this parameter will result in the application receiving an ArrayIndexOutOfBoundsException
exception and will likely require termination. For this reason, we are adding up the length of the largest string as seen in the following code snippet:
private static final String TIME_STRING_PREFIX = "Time: "; private static final String TIME_FORMAT = "00:00:00"; /* Obtain the maximum number of characters that our Text * object will need to display*/ private static final int MAX_CHARACTER_COUNT = TIME_STRING_PREFIX.length() + TIME_FORMAT.length();
In the third step, we are overriding the Text
object's onManagedUpdate()
method in order to apply changes to the Text
object's string after every second passed. At first, we simply obtain the device's current second value, using it to compare with the second value in the previous call to the Text
object's onManagedUpdate()
method. This allows us to avoid updating the Text
object with the system time on every single update. If the previous second that the Text
object's string was updated with is not the same as the new second value, then we continue on to obtain the current minute and hour values as well via the Calendar.getInstance().get(HOUR)
method and MINUTE
variation. Now that we've got all of the values, we build a new string containing the updated time, and call setText(pString)
on the Text
object to change the string it will display on the device.
However, due to the fact that each individual character width might have a different value, we also need to make corrections in the position in order to keep the full Text
object on the screen. By default, the anchor position is set to the center of an Entity
object, so by calling this.setX(WIDTH - this.getWidth() * 0.5f)
, where this
refers to the Text
object, we position the entity's center-most point at the maximum screen width to the right, and then subtract half of the entity's width. This will allow the text to sit right along the edge of the screen even after its characters change the width of the Text
object.
There's more...
Sometimes our games may require a little bit of formatting to the Text
object's strings. In cases where we need to adjust the Text
object's horizontal alignment, apply auto-wrapping to the text if its string exceeds a certain width, or a leading space to the text, we can do these with some very easy-to-use methods. The following methods can be called directly on the Text
object; for example, mText.setLeading(3)
:
setAutoWrap(pAutoWrap)
: This method allows us to define whether or not, and if so, how aText
entity will perform auto-wrapping. The options we have for parameters includeAutoWrap.NONE
,AutoWrap.LETTERS
,AutoWrap.WORDS
, andAutoWrap.CJK
. WithLETTERS
, line break won't wait for a whitespace before breaking to a new line whileWORDS
will. TheCJK
variant is an option which allows auto-wrapping for Chinese, Japanese, and Korean characters. This method should be used alongsidesetAutoWrapWidth(pWidth)
, wherepWidth
defines the maximum width of any single line within theText
object's string, causing line-breaks when necessary.setHorizontalAlign(pHorizontalAlign)
: This method allows us to define the type of alignment theText
object's string should follow. The parameters includeHorizontalAlign.LEFT
,HorizontalAlign.CENTER
, andHorizontalAlign.RIGHT
. The result is similar to what we'd see when setting alignment within a text editor.setLeading(pLeading)
: This method allows us to set a leading space at the beginning of theText
object's string. The parameter required is a float value, which defines the leading width of the sring.
See also
- Using AndEngine font resources in Chapter 1, Working with Entities.
- Overriding the onManagedUpdate method in this chapter.