Code archives/Graphics/TSprite

This code has been declared by its author to be Public Domain code.

Download source code

TSprite by Mahan2009
Ever felt drawing of TImage:s in bmx felt dull? That keeping track of which order they are drawn manually was tedious? That controlling alpha, color, scaling and rotation by making separate function-calls before DrawImage(), and maybe after too to reset the drawing state wasn't an easy way to handle things?

Fear not because here is the TSprite basic sprite system, that will make life easier for you. Just as in the early days of C64 and Amiga you can now create your sprites and control their respective properties and get them drawn automatically as you want them, and in which order you want them drawn.

(This code is mostly aimed at beginners to make life easier, but can easily be extended for intermediate and professional needs)

edit: bugfix, spelling

sprite.bmx:
'
' TSprite - a very basic sprite system.
'
' Although rudimentary it keeps track of each sprites unique properties
' and draws them all to the screen.
'
' zOrder, Accessed through GetzOrder()/SetzOrder(), makes it simple
' for the user to control the order in which they are drawn.
' (the higher the zOrder the later it is drawn and thus appearing "on top"
' of previously draw sprites)
'
' Usage:
'	Create Sprites:
'		local mySprite:TSprite=TSprite.createSprite(image:TImage)
'
'	The createSprite() call also has lots of default params (see source below)
'   to set the sprites initial values.
'
'	Delete Sprites:
'		TSprite.deleteSprite(sprite:TSprite)
'
' 	Draw all sprites:
' 
'		TSprite.drawAll()
' 
'
' A sprite uses a TImage for its appearance. (The same TImage can be used for several sprites.)
'
' More on zOrder: If several sprites share the same zOrder, they are drawn in the order they got
' their zOrder (or where created, if not set manually later, as zOrder is set during creation)
'
'
' Author: Mattias Hansson aka MaHan (2009)
'

Type TSprite

	Const EPSILON:Float = 0.0001
	Const WHITE:Int = $ff
	
	'The sprite list keeps the sprites in drawing order
	Global _spriteList:TList = New TList
	
	Field image:TImage  ' The image-ref containing the sprite appearance 
	Field angle:Float   ' angle (in degrees) of sprite
	Field alpha:Float   ' sprite alpha
	Field blendMode:Int ' sprite blendmode
	Field colorR:Int    ' Red color component
	Field colorG:Int    ' Green color component
	Field colorB:Int    ' blue color component
	Field scaleX:Float  ' horizontal scale (where 1.0 is original size)
	Field scaleY:Float  ' vertical scale (where 1.0 is original size)
	Field x:Int         ' x-position
	Field y:Int         ' y-position
	Field height:Int    ' height of sprite
	Field width:Int     ' width of sprite
	Field _zOrder:Int   ' Z-order of the sprite
	Rem
	bbdoc: Get the zOrder value in this TSprite object.
	End Rem
	Method GetzOrder:Int()
		Return _zOrder
	End Method
	Rem
	bbdoc: Set the zOrder value for this TSprite object.
	End Rem
	Method SetzOrder(Value:Int)
		_zOrder = Value
		_spriteList.Remove(Self)
		Local inserted:Int = False
		For Local sprite:TSprite = EachIn Self._spriteList
			If sprite._zOrder > Self._zOrder Then
				Self._spriteList.InsertBeforeLink(Self, Self._spriteList.FindLink(sprite))
				inserted = True
				Exit
			End If
		Next
		If Not inserted Then
			Self._spriteList.AddLast(Self)
		End If
	End Method
	
	
	Function drawAll()
		For Local sprite:TSprite = EachIn Self._spriteList
			sprite._draw()
		Next
	End Function
	
	Method _draw()
		Local rotated:Int = False
		Local scaled:Int = False
		Local colored:Int = False
		Local alphad:Int = False

				
		'Set rotation and scaling (of not default)
		If (Abs(Self.angle - 0.0) > EPSILON) Then
			rotated = True
		End If
		
		' scale this sprite (if needed)
		If (Abs(Self.scaleX - 1.0) > EPSILON) Or (Abs(Self.scaleY - 1.0) > EPSILON) Then
			scaled = True
		End If

		If scaled Or rotated Then
			SetTransform(Self.angle, Self.scaleX, Self.scaleY)
		End If
		
		If Not ((Self.colorR = WHITE) And (Self.colorG = WHITE) And (Self.colorB = WHITE)) Then
			SetColor(Self.colorR, Self.colorG, Self.colorB)
			colored = True
		End If

		If Not (Self.blendMode = MASKBLEND) Then
			SetBlend(Self.blendMode)
		End If
		
		If (Abs(Self.alpha - 1.0) > EPSILON) Then
			SetAlpha(Self.alpha)
			alphad = True
		End If
		
						
		DrawImage(Self.image, Self.x, Self.y)

		
		If alphad Then
			SetAlpha(1)
		End If
		
		If Not (Self.blendMode = MASKBLEND) Then
			SetBlend(MASKBLEND)
		End If
		
		If colored Then
			SetColor(WHITE, WHITE, WHITE)
		End If

		If scaled Or rotated Then
			SetTransform()
		End If
		
		
	End Method
	
	' factory method
	Function createSprite:TSprite(image:TImage, x:Int = 0, y:Int = 0, zOrder:Int = 0, scaleX:Float = 1.0, scaleY:Float = 1.0, angle:Float = 0, alpha:Float = 1.0, blendmode:Int = MASKBLEND)
		Local ns:TSprite = New TSprite
		
		ns.image = image
		ns.x = x
		ns.y = y
		ns.scaleX = scaleX
		ns.scaleY = scaleY
		ns.angle = angle
		ns.alpha = alpha
		ns.blendMode = blendMode
		ns.colorR = WHITE
		ns.colorG = WHITE
		ns.colorB = WHITE

		ns.SetzOrder(zOrder)
		
		Return ns
	End Function
	
	Function deleteSprite(sprite:TSprite)
		_spriteList.Remove(sprite)
	End Function
	
End Type

Comments

Mahan2009
Here is a demo:

Remember to update this line with your own image (64x64 or 128x128):
Local img:TImage = LoadImage("attack e0000.bmp")

sprite_demo.bmx:

' TSprite demo code
'
' keys:
' 	[KEY_LEFT] [KEY_RIGHT] - move sprite horizontally
'	[A] [D] - rotate sprite
'   [W] [S] - higher or lower zOrder
'   [Q] [E] - adjust alpha
'   [RETURN] - add a sprite at runtime.
'   [BACKSPACE] - delete a sprite at runtime
'

Include "sprite.bmx"

Graphics 800, 600

AutoMidHandle(True)

Local img:TImage = LoadImage("attack e0000.bmp") ' Change to load your own image here. Any 64x64 or 128x128 should do fine.

Local spr1:TSprite = TSprite.createSprite(img, 100, 100)
Local spr2:TSprite = TSprite.createSprite(img, 300, 100)

spr1.blendMode = ALPHABLEND

Local spr3:TSprite = Null

While Not KeyDown(Key_Escape)
	Cls

	' move sprite x
	If KeyDown(KEY_RIGHT) Then spr1.x:+1
	If KeyDown(KEY_LEFT) Then spr1.x:-1
	
	' rotate mage
	If KeyDown(KEY_A) Then spr1.angle:-1
	If KeyDown(KEY_D) Then spr1.angle:+1
	
	' set zOrder
	If KeyDown(KEY_W) Then spr1.SetzOrder(1)
	If KeyDown(KEY_S) Then spr1.SetzOrder(-1)

	' adjust alpha	
	If KeyDown(KEY_Q) Then spr1.alpha:-0.005
	If KeyDown(KEY_E) Then spr1.alpha:+0.005
	
	If KeyDown(KEY_RETURN) And (spr3 = Null) Then spr3 = TSprite.createSprite(img, 500, 100)
	If KeyDown(KEY_BACKSPACE) And Not (spr3 = Null) Then TSprite.deleteSprite(spr3) ; spr3 = Null
	
	TSprite.drawAll()
	
	Flip 1
Wend




Chroma2010
Nice piece of work to study. Thanks for this.


Code Archives Forum