The purpose of this post is to help people build better programs.
In this case how to
make text look the same on every computer running your games.
This is a working system of using bitmap fonts, complete with 10 prepared fonts which you can paste directly into your game.
Zero mucking around needed. Copy and paste code.
The Problem.
If you ever tried to get someone else to play your game you figured out they can't see your custom fonts.
The built-in system requires you to install windows fonts. Nobody does this.
So I decided I'd solve the problem and finally make a bitmap based text system. This way the game doesn't rely on the windows font system.
Creating Bitmap Fonts.
This could be a real pain in photoshop. Luckily someone posted a free app to make this quick.
This is Bitmap Font Creator written by Hubdule.
Thread Including Download Here:
http://forum.thegamecreators.com/?m=forum_view&t=189225&b=41
All of the fonts in this example were prepared with this app.
You can easily swap in any number of other fonts.
How It Works.
The app creates one big image file with all of the characters.
Then we can split them up in DBP, scale and color them.
A text file is created that stores all of the coordinates to make it easy.
Working Demo.
The demo and all source files can be downloaded on the bottom right.
`Written By Mage, Sept. 2013
`Global Font Variables
dim bfont_image(10) as integer
dim bfont_char(10, 130) as integer
dim bfont_aspect#(10, 130)
dim bfont_kerning#(10)
`Global Shared Font Variables
global bfont_size as integer
global bfont_color as integer
global bfont_type as integer
global bfont_freeobjectpool as integer
global bfont_alpha as integer
`Set Display Settings
Set Display Mode 1024, 768, 32
AutoCam Off
Sync On
Sync Rate 0
`Init Font System
BFont_Init()
`Set Shared Font Size
BFont_SetSize(50)
`Main Loop - Display fonts centered to screen with their names.
Do
BFont_SetType(0)
BFont_SetColor(RGB(255,255,255))
BFont_CenterText(Screen Width() / 2, 100, "La Reyna Catalina NF")
BFont_SetType(1)
BFont_SetColor(RGB(255,0,0))
BFont_CenterText(Screen Width() / 2, 150, "BadaBoom BB")
BFont_SetType(2)
BFont_SetColor(RGB(0,255,0))
BFont_CenterText(Screen Width() / 2, 200, "Anglepoise Lampshade")
BFont_SetType(3)
BFont_SetColor(RGB(0,0,255))
BFont_CenterText(Screen Width() / 2, 250, "Bolide MF")
BFont_SetType(4)
BFont_SetColor(RGB(255,255,0))
BFont_CenterText(Screen Width() / 2, 300, "Babelfish")
BFont_SetType(5)
BFont_SetColor(RGB(0,255,255))
BFont_CenterText(Screen Width() / 2, 350, "Living Hell")
BFont_SetType(6)
BFont_SetColor(RGB(220,220,220))
BFont_CenterText(Screen Width() / 2, 400, "Biometric Joe")
BFont_SetType(7)
BFont_SetColor(RGB(190,190,190))
BFont_CenterText(Screen Width() / 2, 450, "Beethoven")
BFont_SetType(8)
BFont_SetColor(RGB(160,160,160))
BFont_CenterText(Screen Width() / 2, 500, "Amiga Forever")
BFont_SetType(9)
BFont_SetColor(RGB(130,130,130))
BFont_CenterText(Screen Width() / 2, 550, "Arcade")
`Draw frame to screen
Sync
Loop
End
`Draw Text - Centered to coords
Function BFont_CenterText(textX, textY, textstring$)
`Stores X value for current character being drawn
xOffset = 0
`Run through and figure out the width of the string of text so it can be later centered.
For i = 1 to Len(textstring$)
`Extract the current character
curChar$ = Mid$(textString$, i)
`Get the numerical character code
curCode = ASC(curChar$)
`Make sure the number isn't too high
If curCode < 130
`Make sure the character exists
If bfont_Char(bfont_type, curCode) > 0
`Make sure the actual character sprite exists
If Sprite Exist(bfont_Char(bfont_type, curCode)) = 1
`Scale the character to current set size
Size Sprite bfont_Char(bfont_type, curCode), bfont_Aspect#(bfont_type, curCode) * bfont_size, bfont_size
`Color the character to current set color
Set Sprite Diffuse bfont_Char(bfont_type, curCode), RGBR(bfont_color), RGBG(bfont_color), RGBB(bfont_color)
`Set the character to current set transparency
Set Sprite Alpha bfont_Char(bfont_type, curCode), bfont_alpha
`Add the Character sprites width to a total text string width.
xOffset = xOffset + bfont_kerning#(bfont_type) * (Sprite Width(bfont_Char(bfont_type, curCode)))
EndIf
EndIf
EndIf
`If character was a space then insert a space by moving current X value.
If curChar$ = " "
xOffset = xOffset + bfont_kerning#(bfont_type) * 0.1 * (bfont_size)
EndIf
Next i
`Set the current x value to begin drawing characters but adjust for centering text
xCursor = textX - (xOffset / 2)
`Run through and draw all of the characters in the text string
For i = 1 to Len(textstring$)
`Extract the current character
curChar$ = Mid$(textString$, i)
`Get the numerical character code
curCode = ASC(curChar$)
`Make sure the number isn't too high
If curCode < 130
`Make sure the character exists
If bfont_Char(bfont_type, curCode) > 0
`Make sure the actual character sprite exists
If Sprite Exist(bfont_Char(bfont_type, curCode)) = 1
`Draw Character to screen at current XY values.
Paste Sprite bfont_Char(bfont_type, curCode), xCursor, textY
`Move the X value to next characters x position. Accounts for different character widths plus kerning too.
xCursor = xCursor + bfont_kerning#(bfont_type) * (Sprite Width(bfont_Char(bfont_type, curCode)))
EndIf
EndIf
EndIf
`If character was a space then insert a space by moving current X value.
If curChar$ = " "
xCursor = xCursor + bfont_kerning#(bfont_type) * 0.1 * (bfont_size)
EndIf
Next i
EndFunction
`Initialize The Font System
Function BFont_Init()
`Tell The Font System Where It can begin grabbing and using free image/sprite index numbers.
bfont_freeobjectpool = 1000
`Load Font Images
For i = 0 to 9
bfont_image(i) = BFont_GetFreeObj(0)
Load Image "Font\" + str$(i) + "\font.png", bfont_image(i)
Next i
`Generate Font Sprites - For some reason this needed to be done after all the images loaded. Or it garbled.
For i = 0 to 9
BFont_MakeChars(i)
bfont_kerning#(i) = 0.6
Next i
`Kerning Tweaks
bfont_kerning#(5) = 0.7
bfont_kerning#(7) = 0.7
bfont_kerning#(8) = 0.7
`Set Shared Variables
bfont_size = 12
bfont_color = RGB(255, 255, 255)
bfont_type = 0
bfont_alpha = 255
EndFunction
`Generates Font Sprites - Input is fonts index number
Function BFont_MakeChars(btype)
`Get Height and Width of font image.
iWidth# = Image Width(bfont_image(btype))
iHeight# = Image Height(bfont_image(btype))
`Open the Font data file containing texture coordinate info, and generate all characters.
Open To Read 1, "Font\" + str$(btype) + "\font.txt"
While File End(1) = 0
`Read current characters data.
Read String 1, cLine$
`Separate current characters data.
`Characters ASCII Character Code.
cCHR = Val(First Token$(cLine$, ":"))
`Character X Value
cX# = Val(Next Token$(":"))
`Character Y Value
cY# = Val(Next Token$(":"))
`Character Width
cW# = Val(Next Token$(":"))
`Character Height
cH# = Val(Next Token$(":"))
`Make sure character code is valid and height is non-zero (prevents divide by zero)
If cCHR > 0 and cCHR < 130 and cH# > 0
`Get an unused sprite index
cNum = BFont_GetFreeObj(0)
`Create Sprite for character - at this point it's huge and is the entire font image
Sprite cNum, 0, 0, bfont_image(btype)
`Make The Character Sprite Just show the intended character.
SET SPRITE TEXTURE COORD cNum, 0, cX# / iWidth#, cY# / iHeight#
SET SPRITE TEXTURE COORD cNum, 1, (cX# + cW#) / iWidth#, cY# / iHeight#
SET SPRITE TEXTURE COORD cNum, 2, cX# / iWidth#, (cY# + cH#) / iHeight#
SET SPRITE TEXTURE COORD cNum, 3, (cX# + cW#) / iWidth#, (cY# + cH#) / iHeight#
`Record the aspect ratio of the character for scaling later. Since these are not square characters.
cAspect# = cW# / cH#
bfont_aspect#(btype, cCHR) = cAspect#
`Scale Character to native size. Otherwise it's enormous if programmer forgets to set text size.
Size Sprite cNum, cW#, cH#
`Hide the sprite.
Hide Sprite cNum
`Record the sprite index into the font system.
bfont_char(btype, cCHR) = cNum
EndIf
EndWhile
Close File 1
EndFunction
`Draw Text - At given coords
Function BFont_Text(textX, textY, textstring$)
`Stores X value for current character being drawn
xCursor = textX
`Run through and draw each character in the string
For i = 1 to Len(textstring$)
`Extract the current character
curChar$ = Mid$(textString$, i)
`Get the numerical character code
curCode = ASC(curChar$)
`Make sure the number isn't too high
If curCode < 130
`Make sure the character exists
If bfont_Char(bfont_type, curCode) > 0
`Make sure the actual character sprite exists
If Sprite Exist(bfont_Char(bfont_type, curCode)) = 1
`Scale the character to current set size
Size Sprite bfont_Char(bfont_type, curCode), bfont_Aspect#(bfont_type, curCode) * bfont_size, bfont_size
`Color the character to current set color
Set Sprite Diffuse bfont_Char(bfont_type, curCode), RGBR(bfont_color), RGBG(bfont_color), RGBB(bfont_color)
`Paste the character to current X,Y values
Paste Sprite bfont_Char(bfont_type, curCode), xCursor, textY
`Set the character to current set transparency
Set Sprite Alpha bfont_Char(bfont_type, curCode), bfont_alpha
`Move the X value to next characters x position. Accounts for different character widths plus kerning too.
xCursor = xCursor + bfont_kerning#(bfont_type) * (Sprite Width(bfont_Char(bfont_type, curCode)))
EndIf
EndIf
EndIf
`If character was a space then insert a space by moving current X value.
If curChar$ = " "
xCursor = xCursor + bfont_kerning#(bfont_type) * 0.1 * (bfont_size)
EndIf
Next i
EndFunction
rem returns next free object starting from free object marker
Function BFont_GetFreeObj(MyCount)
RetVal = bfont_freeobjectpool
While (MyCount => 0)
Repeat
RetVal = RetVal + 1
Until Object Exist(RetVal) = 0 And Image Exist(RetVal) = 0 And Sprite Exist(RetVal) = 0
MyCount = MyCount - 1
EndWhile
EndFunction RetVal
`Set Font Alpha
Function BFont_SetAlpha(alphavalue)
bfont_alpha = alphavalue
EndFunction
`Set Font Color
Function BFont_SetColor(rgbVal)
bfont_color = rgbVal
EndFunction
`Set Current Fonts Kerning - This is the spacing between characters.
Function BFont_SetKerning(kernvalue#)
bfont_kerning#(bfont_type) = kernvalue#
EndFunction
`Set Font Pixel Height
Function BFont_SetSize(fontsize)
bfont_size = fontsize
EndFunction
`Set Current Font
Function BFont_SetType(fonttype)
bfont_type = fonttype
EndFunction
I've included 10 prepared fonts. Use any scale, any color.
There's a centering text feature built-in too.
You can basically drag and drop it into any DBP project.
Just make sure you put the font folder in your project too.
Further Improvements.
I tried to balance some speed with this, while avoiding the need for people to install plugins.
The text could be anti-aliased better, likely at the cost of speed.
You could also adjust the font image in the font creator.
Sometimes the kerning/spacing is off by a pixel. I've left it in this example again for speed.
I find it's a bit slower than Windows Font based methods, but it's still fast enough for games.
This work is improved and based upon this discussion:
http://forum.thegamecreators.com/?m=forum_view&t=189225&b=41
See my previous tip here...
http://forum.thegamecreators.com/?m=forum_view&t=205649&b=1
Update: Forgot to include transparency support so I added it.