|
To solve the problem of cross platform font support in an OpenGL environment, I developed a custom font processor in the game engine. A file containing the font model data is the only requirement for using fonts. As such, I supplied a very simple font that uses very few polygons called "Basic". You can use the this font or you can make your own. If you understand how to make models using the glo file format then you'll have no problem making fonts. That is because the font files format (glf) is exactly the same as the glo file format except that it accepts an extra keyword, START xxx, where xxx is a three digit ASCII value. The font file format is simply a list of models in glo format separated by the START xxx keyword.
Warnings about using the Basic font
Basic.glf contains all capital letters, all ten numbers, the period and the colon. It does not contain any other ASCII character. So, if you try to use a character that is not contained in the file (small letters for example), your program will crash. You can avoid crashes by not using those characters, by adding those characters to the file or by waiting until I release a game with those characters appended to the file. But, don't expect future game engines to more robust. I don't believe in writing error handling code for personal projects.
The Code
Actor[] aScore = new Actor[6];
GLFont fntBasic;
int score
Three new global variables are introduced here. The first, aScore[] is an array of 6 actors which is used to display the score. fntBasic is a reference to the font that will display the score (among other things). And finally, score manages the current score.
private void addScore(int a)
{ int s, v;
s = score += a;
for(int t=0; t<6; t++)
{ v = s%10;
s /= 10;
gEngine.setGLLetter(fntBasic, aScore[t], v+48);
}
This method accepts the integer parameter, a, and adds it to score. The actors that display the score are then updated to reflex this change of score. It does this by iterating through the six score digits. By successively dividing the score by 10 each iteration, successive powers of ten (the next digit) are derived with the modulo operator. Then, the digit's actor is is updated with the setGLLetter method.
gEngine.glFonts.add(fntBasic = new GLFont(getCodeBase() + "Basic.glf"));
while(gEngine.modelCount<4) sleep(100)
A good time to load fonts is when the models are loading. Use the glFonts.add() method to load fonts. Since loading fonts is like loading models, we should wait until all fonts are loaded before proceeding. Although there may be numerous models in a single font file, modelCount is only incremented by one for the entire collection of fonts. So, we now wait for 4 models (instead of 3 models) to load before proceeding.
aPlayer = gEngine.addActor(mPlayer, 0, 0, -200); // From previous lessons
gEngine.print(fntBasic, "SCORE:", -16f, 15f, -39f);
for(int t=0; t<6; t++)
aScore[t] = gEngine.addGLLetter(fntBasic, 48, -8f-((float)t/1.4f), 15f, -39f);
addRocks(4); // From previous lesson
Now, all we need to do is print SCORE: to the top of the display and initialize the six actors which will represent the score. Notice, that SCORE: is printed with the print() method but the score is not. That is because SCORE: remains static throughout the game but we need references to the score digits so that they may be updated at any time.
A Snippet From Basic.glf
START 046
COMPILE
USERCS
BEGIN_TRIANGLES
1 0 0 1 1 0 2 1 0
1 0 0 2 1 0 2 0 0
END
ENDLIST
START 048
COMPILE
USERCS
BEGIN_TRIANGLES
1.0 0.0 0.0 0.0 1.0 0.0 1.0 4.0 0.0
0.0 1.0 0.0 0.0 4.0 0.0 1.0 4.0 0.0
0.0 4.0 0.0 1.0 5.0 0.0 2.0 4.0 0.0
1.0 5.0 0.0 2.0 5.0 0.0 2.0 4.0 0.0
2.0 4.0 0.0 2.0 5.0 0.0 3.0 4.0 0.0
2.0 4.0 0.0 3.0 4.0 0.0 3.0 1.0 0.0
2.0 4.0 0.0 3.0 1.0 0.0 2.0 0.0 0.0
1.0 0.0 0.0 2.0 1.0 0.0 2.0 0.0 0.0
1.0 1.0 0.0 2.0 1.0 0.0 1.0 0.0 0.0
END
ENDLIST
START 049
COMPILE
USERCS
BEGIN_TRIANGLES
1.0 5.0 0.0 2.0 0.0 0.0 1.0 0.0 0.0
1.0 5.0 0.0 2.0 5.0 0.0 2.0 0.0 0.0
END
ENDLIS
This is a snippet from the font file, Basic.glf. It looks a lot like a glo file because it uses the glo file format to load the font models. The only difference between the glf and the glo is the START xxx keyword which specifies which ASCII character to assign to the following model. I listed my models in order. However, order is not important. The Z model can come before the A model as long as it is specified in START xxx. Finally, I would like to note the USERCS keyword. It is a valid glo keyword but are no implementations for models, just fonts. What is does is allow the color and scale to be specified at runtime. That is how my playable Asteroids can have four different colored fonts. Refer to the source code for that game to see an example of how to load a font with a different color and scale.
Your applet should now displays four rocks moving across the display. The player's space craft is visible, centered in the display. Pressing shift will fire bullets from the space craft. The left and right arrows will rotate the craft. The up and down arrows will provide movement and stopping and SCORE: 000000 is displayed at the top of the screen.
|