## Rendering Numbers An Excursion

We have an asset image called numbers.png that contains all digits from 0 to 9 plus a dot. Each digit is 20! 32 pixels, and the dot is 10! 32 pixels in size. The digits are arranged from left to right in ascending order. The high-scores screen should display five lines, each line showing one of the five high scores. One such line would start with the high score's position (e.g., "1." or "5."), followed by a space, followed by the actual score. How can we do that?

We have two things at our disposal: the numbers.png image and Graphics.drawPixmap(), which allows us to draw portions of an image to the screen. Say we want the first line of the default high scores (with the string "1. 100") to be rendered at (20, 100) so that the top-left corner of the digit 1 coincides with those coordinates. We call Graphics.drawPixmap() like this:

game.getGraphics().drawPixmap(Assets.numbers, 20, 100, 20, 0, 20, 32);

We know that the digit 1 has a width of 20 pixels. The next character of our string would have to be rendered at (20+20,100). In the case of the string "1. 100," this character is the dot, which has a width of 10 pixels in the numbers.png image:

game.getGraphics().drawPixmap(Assets.numbers, 40, 100, 200, 0, 10, 32);

The next character in the string needs to be rendered at (20+20+10,100). That character is a space, which we don't need to draw. All we need to do is advance on the x-axis by 20 pixels again, as we assume that's the width of the space character. The next character, 1, would therefore be rendered at (20+20+10+20,100). See a pattern here?

Given the coordinates of the upper-left corner of our first character in the string, we can loop through each character of the string, draw it, and increment the x-coordinate for the next character to be drawn by either 20 or 10 pixels, depending on the character we just drew.

We also need to figure out which portion of the numbers.png image we should draw given the current character. For that we need the x- and y-coordinates of the upper-left corner of that portion, as well as its width and height. The y-coordinate will always be zero, which should be obvious when looking at Figure 6-1. The height is also a constant; 32 in our case. The width is either 20 pixels (if the character of the string is a digit) or 10 pixels (if it is a dot). The only thing that we need to calculate is the x-coordinate of the portion in the numbers.png image. We can do that by using a neat little trick.

The characters in a string can be interpreted as Unicode characters or as 16-bit integers. This means that we can actually do calculations with those character codes. By a lucky coincidence, the characters 0 to 9 have ascending integer representations. We can use that fact to calculate the x-coordinate of the portion of the number.png image for a digit like this:

char character = string.charAt(index); int x = (character - '0') * 20;

That will give us 0 for the character 0, 3 ! 20 = 60 for the character 3, and so on. That's exactly the x-coordinate of the portion of each digit. Of course, this won't work for the dot character, so we need to treat that specially. Let's summarize this in a method that can render one of our high-score lines given the string of the line and the x- and y-coordinates that the rendering should start at.

public void drawText(Graphics g, String line, int x, int y) { int len = line.length(); for (int i = 0; i < len; i++) {

char character = line.charAt(i);

int srcX = 0; int srcWidth = 0; if (character == '.') { srcX = 200; srcWidth = 10; } else {

g.drawPixmap(Assets.numbers, x, y, srcX, 0, srcWidth, 32); x += srcWidth;

We iterate over each character of the string. If the current character is a space, we just advance the x-coordinate by 20 pixels. Otherwise we calculate the x-coordinate and width of the current character's region in the numbers.png image. The character is either a digit or a dot. We then render the current character and advance the rendering x-coordinate by the width of the character we've just drawn. This method will of course blow up if our string contains anything other than spaces, digits, and dots. Can you think of a way to make it work with any string?