Score effect technique

BlitzMax Forums/BlitzMax Programming/Score effect technique

SpaceAce(Posted 2007) [#1]
I'm thinking of adding a feature to one of my games where, when the player scores points, the number of points pops up at the place where the scoring action happened then flitters off/spins/cycles colors/whatever. I am worried about the overhead of creating images on the fly, though. I could use text labels but I would prefer to use graphical representations of the scores because I can easily manipulate them using sswift's sprite library.

What's the best method for this kind of on-the-fly graphics creation? Should I pre-render the numbers 0-9 then cobble them together to form the scores or should I clear the buffer and DrawText() to it or are there even better options?

Thanks,
SpaceAce


FlameDuck(Posted 2007) [#2]
Why does it need to be on the fly?


LarsG(Posted 2007) [#3]
use a bmp font..
Make your own custom drawtext() function, and get it to display the text and number to your liking..
rotate and zoom and fade or whatever you want on the "score" numbers..


SpaceAce(Posted 2007) [#4]
FlameDuck - The score achieved could be nearly anything at any time. I also want to change the appearance of the score, so "700" doesn't always look the same.

LarsG - That's pretty much where I am right now, but I'm hoping not to reinvent the wheel when sswift's sprite library makes easy so many of the things I want to achieve.

SpaceAce


ImaginaryHuman(Posted 2007) [#5]
DrawText DOES draw each digit individually, based on pre-rendered images of those digits. You could make your own to do the same if you wanted.


sswift(Posted 2007) [#6]
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.


sswift(Posted 2007) [#7]
Here is some example code for how to use the system:

Font1 = Font.Load("gfx\font1.png", 24, 28, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzÀÁÄÅÆÇÈÑÖØÜ®àáäåæçèéñöøüþ0123456789¿?!:-+=þ/¡'%;_.¤"+ Chr$(34) + Chr$(126) + "<>«»†¨±²,`‘©@$^&*|{}[]()" + Chr$(32))


	' -------------------------------------------------------------------------------------------------------------------------------------------------------
	' This function spawns floating text at the specified location.
	' Effect 1 = Text floats upwards with increasing speed and decreasing transparency.
	' Effect 2 = Text expands in place while decreasing in transparency.
	' -------------------------------------------------------------------------------------------------------------------------------------------------------
				
		Function SpawnText(NewText$, X#, Y#, Effect%=1)
		
			Local T:Text
			
			Font1.Set()
			
			T = Text.Create(NewText$, X#, Y#, ORDER_FLOATING_TEXT)
				
				Select Effect
				
					Case 1
				
						T.Pivot.SetScale(1.25)
				
						Animate.SetExponent(3.5)
						T.Pivot.AnimateY(Y#, Y#-300, 2000, MODE_SPEEDUP_EXP)
				
						Animate.SetExponent(8.0)
						T.Pivot.AnimateAlpha(1, 0, 2000, MODE_SPEEDUP_EXP)
						
					Case 2
					
						Animate.SetExponent(3.5)
						T.Pivot.AnimateScale(1.25, 3.25, 500)', MODE_SPEEDUP_EXP)
				
						Animate.SetExponent(8.0)
						T.Pivot.AnimateAlpha(1, 0, 500, MODE_SPEEDUP_EXP)
							
				End Select		
			
		End Function




smilertoo(Posted 2007) [#8]
wierd, i created a little sprite routine that does just that.


SpaceAce(Posted 2007) [#9]
Wow, sswift, thanks. I'll get to looking at that code right away. I've only used your sprite library for one thing in my current project (animating explosions), but it paid for itself with that alone. This is just icing, thanks again.

smilertoo - I suspect that several people have, which is why I came here before starting from scratch :)

SpaceAce


SpaceAce(Posted 2007) [#10]
I'm bumping this for sheer awesomeness. Anyone looking for a great sprite library (and now font library) should really talk to sswift. I can't believe how easy the sprite library and this font add-on have made it for me to design cool text effects.

SpaceAce