Graphic Text
1. Graphic Text
2. Getting the Graphic Digits
3. Setting things up for output
4. Breaking Down the Number
5. The Score Area Object
6. Final Thoughts
1) Graphic Text
In many games you tend to use an extremely unique stylized font for your text. There are various ways to add fonts although I tend to simply add the images of the font I want and display the images in the configuration of the words I want. In this basic program, I included the method I use to do this with graphic digits as many games have some kind of number display that changes as the player scores.
2) Getting the Graphic Digits
The first thing you'll want to do is get the graphic digits that you'll use to display your numbers. Here are the images of the digits we'll use:
Each of those digits is in a separate file. To get those digits into our program we'll use the asset manager, so we'll pass that in now. If you're not familiar with the asset manager, you can see my tutorial for my asset manager class here. Here's the relevant code:
private void load_graphic_digits() {
Texture number_0;
Texture number_1;
Texture number_2;
Texture number_3;
Texture number_4;
Texture number_5;
Texture number_6;
Texture number_7;
Texture number_8;
Texture number_9;
number_0 = assetMgr.getImgNum("0.png");
number_1 = assetMgr.getImgNum("1.png");
number_2 = assetMgr.getImgNum("2.png");
number_3 = assetMgr.getImgNum("3.png");
number_4 = assetMgr.getImgNum("4.png");
number_5 = assetMgr.getImgNum("5.png");
number_6 = assetMgr.getImgNum("6.png");
number_7 = assetMgr.getImgNum("7.png");
number_8 = assetMgr.getImgNum("8.png");
number_9 = assetMgr.getImgNum("9.png");
score_digits = new Array<Texture>();
score_digits.add(number_0);
score_digits.add(number_1);
score_digits.add(number_2);
score_digits.add(number_3);
score_digits.add(number_4);
score_digits.add(number_5);
score_digits.add(number_6);
score_digits.add(number_7);
score_digits.add(number_8);
score_digits.add(number_9);
} // END load_graphic_digits
That code loads each image of a digit into an array spot. The array and graphics in each array spot are below after the above method runs:
So if we access array spot "4", we'll get the image in the "array index" that has a 4, which is the image "4".
3) Setting things up for output
Now that we have the basic array setup with the number images, we'll load these images into our program and keep track of the width of each digit, assuming that each digit is the same width. If not, this class can be updated to use different width images, which is an exercise left up to the student. Here's the full contructor:
public GraphicDigits(AssetMgr assetMgr) {
this.assetMgr = assetMgr;
load_graphic_digits();
// this assumes all numbers are the same width
digitWidth = assetMgr.getImgNum("0.png").getWidth();
return_digits = new Array<Texture>();
} // END GraphicDigits
4) Breaking Down the Number
Ok, now we get to the "meat" of the class. The main method here, which is called from the main GameScreen, is called "getDigitImages". It basically takes an array of digits and a number and returns an array with the graphic representation of those numbers which can be displayed. Here's how it works:
The first thing we do is translate the number passed in into a string. Then we split the string into separate array spots so we have an array of the digits in the number.
public Array<Texture> getDigitImages(Array<Texture> output_digits, int num) {
// remove all entries from last call
return_digits.clear();
// make the integer score into a string
strValue = String.format("%s", num);
// break the digits up into individual array spots
digits = strValue.toCharArray();
So, for example, if we pass in the number "3742" the array will look like this:
Now we loop through the digit array we just created. It's basically 1 line of code and a loop, but it's a tad difficult to understand, so we'll go through it. Here's the loop:
for(char letter : digits) {
return_digits.add( output_digits.get(Integer.valueOf(letter-48) ) );
} // END for
We'll start from the inner most code and move outward. The inner most code is:
letter-48
Here "letter" is going to be the ASCII representation of the number, in this case "3". The ASCII representation of numbers starts with "0", which is ASCII 48. What this means is, using ASCII values, the number "0" is ASCII 48, "1" is ASCII 49, etc. We'll subtract the value of "0" from our "letter" to get a number. So the ASCII representation of the number "3" is "51". 51 (letter) minus 48 equals 3, which is the array spot we need. So replacing the number into that line, it would look like this:
return_digits.add( output_digits.get(Integer.valueOf(3) ) );
Now we'll look at the next part, which is the "Integer.valueOf" portion. All this does is translate the part inside the parens into an integer. So in our case, it is translating the char "3" to the integer "3". So, replacing that we have the following:
return_digits.add( output_digits.get(3) );
The next portion to look at is the "output_digits.get" part. What this does is get the value at the array spot passed in. This is what the "output_digits" array looks like:
The "get" method of that array gets the spot of the number passed in as you would expect. So the line we have here would get the "3" spot. So now, we basically have this:
return_digits.add( );
So now this code is pretty readable by itself. It simply adds the image of a 3 to the return digits array. This process is repeated for each digit in the number we want rendered. Once each of the images is added to the return array, it looks like this:
Now this array with the numeric representation of our number is returned to the calling method. In this case it is called from the scoreArea object.
5) The Score Area Object
Our scoreArea object simply displays the score which is passed into the graphic text object. Here's the entire class:
package com.games;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.utils.Array;
public class ScoreArea {
GraphicDigits gDigits;
Array<Texture> output;
int score;
float x,y;
float scoreDigitWidth;
private float baseX;
public ScoreArea(AssetMgr assetMgr, GraphicDigits gDigits) {
this.gDigits = gDigits;
score = 0;
scoreDigitWidth = assetMgr.getImgNum("0.png").getWidth();
// this is the base of where the number starts
baseX = 600;
} // END score area
//**************************************
public void update() {
output = gDigits.getDigitImages(gDigits.score_digits, score);
} // END update
//********************************************************************
public Array<Texture> getScoreDigits() {
return output;
} // END getScoreDigits
/********************************************************
*
* @param digitSpot - the current array spot for digits of the current score
* @return
*/
public float getX(int digitSpot) {
// first num below is where the default output starts.
// Each successive number moves to the left
x = baseX-(scoreDigitWidth*(output.size-digitSpot-1));
return x;
} // END getX
public float getY() {
y = 400;
return y;
} // END getY
}
The main thing that it does is get the array of graphic digits from the graphic text object and position the digits in the desired area on the screen. So once we get the array of digits we have a loop in the render function loop through the digits and display the correct digit. Here's the loop from our render method:
public void showScore(SpriteBatch batch) {
allDigits = scoreArea.getScoreDigits();
// loop through digits passed back
if(allDigits != null) {
int i = 0;
for(Texture img : allDigits) {
batch.draw(img, scoreArea.getX(i), scoreArea.getY());
i++;
} // END for
} // END if
} // END show score
This code gets the digits from the scoreArea object and loops through each digit while keeping track of the index of each digit. When going through this, the digits start on the right. So if the number has 1 digit, it will be at the point of the baseX value given in scoreArea, baseX being the x coordinate of where we start the score output. If it has 2 digits, the "ones" digit will be at the baseX point, and the "tens" digit will be at the baseX point minus the width of each digit. This continues until the full digit is displayed.
6) Final Thoughts
This method can be easily modified to accommodate letters as well. I've only done the number specific version because in my games because I've tended to use Photoshop to create and display images of entire words done in Photoshop. Numbers, however, are routinely required to be based on a constantly updating player score.
Now this scoreArea method could be integrated into GameScreen, although I do it this way because there are times when you'll need to display many different numbers and I'll just have the score area take care of the different score displays.