You want a font system to go with my sprite system? Why didn't you say so! I've got one I'm using in my own game. I don't plan to sell it because you need my sprite system to use it, so here ya go!
Pass this an animimage style image with one letter per frame. You must include a blank frame if you include space. When loading the font, the letters in CharacterSet should be the same order that the letters appear in the image.
Type Font
Global Current:Font
Field _Image:TImage
Field _CharacterSet$
Field _LetterWidth%[]
Field _CelWidth%
Field _CelHeight%
Field _Tracking#
Field _Space#
' -------------------------------------------------------------------------------------------------------------------------------------------------------
' This function loads a font.
'
' The letters in the font image should be centered horizontally and vertically in their respective cels, with the exception of special characters like
' underscores, commas, or quotion marks, which should be placed in the correct vertical position relative to the letters.
'
' The function will determine the width of each letter by examining the alpha information and looking for side regions with an alpha of 0.
'
' Parameters:
' Tracking# = The space between letters. The number of pixels between letters is calculated by multiplying CelWidth% by Tracking#.
' Space# = The width of the space character. As with Tracking#, the width is calculated by multiplying it with CelWidth%.
' -------------------------------------------------------------------------------------------------------------------------------------------------------
Function Load:Font(Filename$, CelWidth%, CelHeight%, CharacterSet$, Tracking#=0.05, Space#=0.33, Flags%=FILTEREDIMAGE|MIPMAPPEDIMAGE)
Local NF:Font
Local Pix:TPixmap
Local Loop%
Local X%, Y%
Local X1#, X2#
NF = New Font
NF._Image = LoadAnimImage(Filename$, CelWidth, CelHeight, 0, Len(CharacterSet$), Flags|DYNAMICIMAGE)
NF._CelWidth = CelWidth
NF._CelHeight = CelHeight
NF._CharacterSet$ = CharacterSet$
NF._Tracking# = Tracking#
NF._Space# = Space#
' Determine the width of each character and store it.
NF._LetterWidth = New Int[Len(CharacterSet$)]
For Loop = 0 To Len(CharacterSet$)-1
' Get a pixmap for the frame of the image that represents this character.
Pix = LockImage(NF._Image, Loop, True, True) 'False)
' Scan down left and right sides, looking for first pixel on each side with an alpha other than 0.
For X = 0 To CelWidth-1
For Y = 0 To CelHeight-1
If ReadPixel(Pix, X, Y)&$FF000000 <> 0
' Mark starting pixel.
' WritePixel(Pix, X, Y, $FF00FF00)
X1# = X
' Exit loops.
X = CelWidth-1
Y = CelHeight-1
EndIf
Next
Next
For X = CelWidth-1 To 0 Step -1
For Y = 0 To CelHeight-1
If ReadPixel(Pix, X, Y)&$FF000000 <> 0
' Mark ending pixel.
' WritePixel(Pix, X, Y, $FFFF0000)
' We use X+1 here because if you imagine there is a single vertical strip, then X2 and X1 will be the same, and that
' would result in a width of 0 when we do X2-X1. But if we add 1, we avoid this issue, and if there are in fact no
' pixels in the letter, then we will still get the width of 0 we desire.
X2# = X+1
' Exit loops.
X = 0
Y = CelHeight-1
EndIf
Next
Next
' Store width. Set width of empty cels to that of a space.
NF._LetterWidth[Loop] = X2#-X1#
If X2#-X1# < 0 Then NF._LetterWidth[Loop] = CelWidth*Space#
' Make sure width is not odd, or else letter will be blurry.
If NF._LetterWidth[Loop] Mod 2 <> 0 Then NF._LetterWidth[Loop] = NF._LetterWidth[Loop] + 1
UnlockImage(NF._Image, Loop)
Next
Return NF
End Function
' -------------------------------------------------------------------------------------------------------------------------------------------------------
' This function sets the font which new text will use.
' -------------------------------------------------------------------------------------------------------------------------------------------------------
Method Set()
Current = Self
End Method
' -------------------------------------------------------------------------------------------------------------------------------------------------------
' This function returns the width of a particular string in the specified font.
' Unprintable characters (including space if it is not in the character set) are replaced with the first character in the font image.
' -------------------------------------------------------------------------------------------------------------------------------------------------------
Method TextWidth#(Text$)
Local Width#
Local Loop%
Local Char$
Local Index%
For Loop = 0 To Len(Text$)-1
' Add the width of this character to the string's width.
Width# = Width# + LetterWidth(Text$[Loop])
' Add space between characters to the string's width.
Width# = Width# + _Tracking#*_CelWidth
Next
' Remove extra space that gets added at the end of the loop.
Width# = Width# - _Tracking#*_CelWidth
Return Width#
End Method
' -------------------------------------------------------------------------------------------------------------------------------------------------------
' This method returns the frame of the font image which is used to represent a specific character.
'
' If the specified character is not in the font's character set, then it returns 0.
' As a result, all characters not in the character set, including space, will look like the first character in the font image.
' -------------------------------------------------------------------------------------------------------------------------------------------------------
Method LetterFrame%(Ascii%)
Local Index%
Index = Instr(_CharacterSet$, Chr$(Ascii)) - 1
If Index < 0 Then Index = 0
Return Index
End Method
' -------------------------------------------------------------------------------------------------------------------------------------------------------
' This method returns the width of the specified letter.
' -------------------------------------------------------------------------------------------------------------------------------------------------------
Method LetterWidth#(Ascii%)
Return _LetterWidth[LetterFrame(Ascii)]
End Method
End Type
Type Text
Field _Text$
Field _Font:Font
Field _Justify%
Field Pivot:Sprite
Field Letter:Sprite[]
' -------------------------------------------------------------------------------------------------------------------------------------------------------
' This function creates a new text object.
'
' A text object is a sprite with no image, with one child sprite for each letter.
' This setup allows one to animate the text in a number of ways simply by animating TextName.Sprite.
'
' Justify: -1=Left, 0=Center, 1=Right
' -------------------------------------------------------------------------------------------------------------------------------------------------------
Function Create:Text(NewText$, X#=0, Y#=0, Order%=0, Parent:Sprite=Null, Justify%=0)
Local NT:Text
NT = New Text
NT._Font = Font.Current
NT._Justify = Justify
NT.Pivot = Sprite.Create(Null, Order, Parent)
NT.Pivot.SetPosition(X#, Y#)
NT.Set(NewText$)
Return NT
End Function
' -------------------------------------------------------------------------------------------------------------------------------------------------------
' This method frees a text object.
' -------------------------------------------------------------------------------------------------------------------------------------------------------
Method Free()
Pivot.Free()
End Method
' -------------------------------------------------------------------------------------------------------------------------------------------------------
' This Function changes the text being displayed on a text object.
' -------------------------------------------------------------------------------------------------------------------------------------------------------
Method Set(NewText$)
Local Loop%
Local X#
Local Index%, Frame%
' Check to make sure the text has changed. If it has not changed, then the text does not need to be recreated.
If _Text$ <> NewText$
' Store new text string.
_Text$ = NewText$
' Free all the letters attached to the text pivot.
Pivot.FreeChildren()
Letter = Null
' Calculate X position of left side of text.
Select _Justify
Case -1 X# = 0
Case 0 X# = -_Font.TextWidth#(NewText$)/2.0
Case 1 X# = -_Font.TextWidth#(NewText$)
End Select
' Create one sprite for each letter, and attach it to the text pivot.
Letter = New Sprite[Len(_Text$)]
For Loop = 0 To Len(_Text$)-1
' Add first half of this letter's width to X.
X# = X# + _Font.LetterWidth#(_Text$[Loop])/2.0
' Create the sprite at this position.
Letter[Loop] = Sprite.Create(_Font._Image, 0, Pivot)
Letter[Loop].SetPosition(X#, 0)
' Set the frame to that of the desired letter.
Letter[Loop].SetFrame(_Font.LetterFrame(_Text$[Loop]))
' Add second half of this letter's width to X.
X# = X# + _Font.LetterWidth#(_Text$[Loop])/2.0
' Add space between characters to X.
' Floor() is used so we don't increment the character positions by fractions of a pixel.
X# = X# + Floor(_Font._Tracking#*_Font._CelWidth)
Next
EndIf
End Method
End Type
To animate the text doing whatever you want with my sprite animation system, just animate TextName.Pivot. You can also do more advanced effects like making the letters move in a sine wave as the pivot they are attached to rises and becomes more transparent, causing the letters to do the same by animating TextName.Letters[] (which will be in pivot space) as well.
This setup doesn't generate any new images, is super flexible, and it should be plenty fast enough for your needs.
|