I’ve whipped up several rough tests:
EDIT 21-MAR-08: Tweaked and improved the tests a little. Added a test incorporating dmaz's list logic.
Array and index-related rendering:
'Particle System Test
'Array and index-related rendering
SuperStrict
Framework BRL.GLMax2D
'Framework BRL.D3D7Max2D
Import BRL.Random
Import BRL.PNGLoader
Global ScreenWidth:Int = 800
Global ScreenHeight:Int = 600
Global MaxParticles:Int = 2000
Global SpriteURL:String = "c:\program files\blitzmax\samples\birdie\games\tiledrop\media\part.png"
'Note: A sprite will automatically be created if one is not found at the url above
Graphics ScreenWidth, ScreenHeight, 32
TParticle.Init MaxParticles, SpriteURL
Local Renders:Int, FPS:Int
Local CurrentMS:Int, OldMS:Int
Local MemAlloced:Int = GCMemAlloced()
SetBlend ALPHABLEND
MoveMouse ScreenWidth / 2, ScreenHeight / 2
While Not KeyHit(KEY_ESCAPE)
Cls
TParticle.Spawn MouseX(), MouseY()
TParticle.RenderLive
If KeyHit(KEY_M) Then MemAlloced = GCMemAlloced()
SetColor 255, 255, 255
SetAlpha 1.0
SetScale 1.0, 1.0
Renders :+ 1
CurrentMS = MilliSecs()
If (CurrentMS - OldMS) >= 1000
OldMS = CurrentMS
FPS = Renders
Renders = 0
EndIf
DrawText FPS + " FPS", 10, 10
DrawText "Memory: " + MemAlloced + " bytes", 10, 30
DrawText "Live particles: " + TParticle.QtyAlive, 10, 70
DrawText "Press M to refresh memory useage value.", 10, ScreenHeight - 30
Flip 0
Wend
End
Type TParticle
Const STATUS_DEAD:Int = 0
Const STATUS_LIVE:Int = 1
Global Particles:TParticle[]
Global QtyAlive:Int
Global ParticleImage:TImage
Function Init(qty:Int, img_url:String= "")
Local pixmap:TPixmap = LoadPixmap(img_url)
If pixmap Then
Pixmap = ResizePixmap(pixmap, 64, 64)
ParticleImage = LoadImage(pixmap)
Else
ParticleImage = createSprite()
EndIf
Particles = New TParticle[qty]
For Local i:Int = 0 To Particles.length - 1
Particles[i] = New TParticle
Next
QtyAlive = 0
pixmap = Null
GCCollect
EndFunction
Function Spawn(x:Int, y:Int)
If QtyAlive < Particles.length
QtyAlive :+ 1
Particles[QtyAlive - 1].X = x
Particles[QtyAlive - 1].Y = y
Particles[QtyAlive - 1].XDir = Rnd(-0.1, 0.1)
Particles[QtyAlive - 1].YDir = Rnd(-0.1, 0.1)
Particles[QtyAlive - 1].R = Rand(32, 255)
Particles[QtyAlive - 1].G = Rand(32, 255)
Particles[QtyAlive - 1].B = Rand(32, 255)
Particles[QtyAlive - 1].Size = Rnd(0.1, 0.5)
Particles[QtyAlive - 1].Alpha = 1.0
EndIf
EndFunction
Function RenderLive()
For Local i:Int = 0 To QtyAlive - 1
If Particles[i].Render() = STATUS_DEAD
Local temp:TParticle = Particles[QtyAlive - 1]
temp.Render
Particles[QtyAlive - 1] = Particles[i]
Particles[i] = temp
QtyAlive :- 1
EndIf
Next
EndFunction
'-------------------------------------
Field X:Float, Y:Float
Field XDir:Float, YDir:Float
Field R:Byte, G:Byte, B:Byte
Field Size:Float
Field Alpha:Float
Method Render:Int()
SetColor R, G, B
SetAlpha Alpha
X :+ XDir
Y :+ YDir
SetScale Size, Size
DrawImage ParticleImage, X, Y
Alpha :- 0.00005
Local Dead:Int = False
If Alpha <= 0.0 Then Dead = True
If X < 0 Or X > ScreenWidth Then Dead = True
If Y < 0 Or Y > ScreenHeight Then Dead = True
If Dead Then Return STATUS_DEAD Else Return STATUS_LIVE
EndMethod
EndType
Function CreateSprite:TImage()
Local size:Int = 64
Local img:TImage = CreateImage(size, size, 1, DYNAMICIMAGE|MASKEDIMAGE)
SetBlend SOLIDBLEND
SetColor 255, 255, 255
DrawOval 0, 0, Size, Size
GrabImage(img, 0, 0)
Return img
EndFunction
Array and status-related rendering:
'Particle System Test
'Array and status-related rendering
SuperStrict
Framework BRL.GLMax2D
'Framework BRL.D3D7Max2D
Import BRL.Random
Import BRL.PNGLoader
Global ScreenWidth:Int = 800
Global ScreenHeight:Int = 600
Global MaxParticles:Int = 2000
Global SpriteURL:String = "c:\program files\blitzmax\samples\birdie\games\tiledrop\media\part.png"
'Note: A sprite will automatically be created if one is not found at the url above
Graphics ScreenWidth, ScreenHeight, 32
TParticle.Init MaxParticles, SpriteURL
Local Renders:Int, FPS:Int
Local CurrentMS:Int, OldMS:Int
Local MemAlloced:Int = GCMemAlloced()
SetBlend ALPHABLEND
MoveMouse ScreenWidth / 2, ScreenHeight / 2
While Not KeyHit(KEY_ESCAPE)
Cls
TParticle.Spawn MouseX(), MouseY()
TParticle.RenderLive
If KeyHit(KEY_M) Then MemAlloced = GCMemAlloced()
SetColor 255, 255, 255
SetAlpha 1.0
SetScale 1.0, 1.0
Renders :+ 1
CurrentMS = MilliSecs()
If (CurrentMS - OldMS) >= 1000
OldMS = CurrentMS
FPS = Renders
Renders = 0
EndIf
DrawText FPS + " FPS", 10, 10
DrawText "Memory: " + MemAlloced + " bytes", 10, 30
DrawText "Live particles: " + TParticle.LiveCount, 10, 70
DrawText "Press M to refresh memory useage value.", 10, ScreenHeight - 30
Flip 0
Wend
End
Type TParticle
Const STATUS_DEAD:Int = 0
Const STATUS_LIVE:Int = 1
Global Particles:TParticle[]
Global LiveCount:Int
Global ParticleImage:TImage
Function Init(qty:Int, img_url:String= "")
Local pixmap:TPixmap = LoadPixmap(img_url)
If pixmap Then
Pixmap = ResizePixmap(pixmap, 64, 64)
ParticleImage = LoadImage(pixmap)
Else
ParticleImage = createSprite()
EndIf
Particles = New TParticle[qty]
For Local i:Int = 0 To Particles.length - 1
Particles[i] = New TParticle
Particles[i].Status = STATUS_DEAD
Next
LiveCount = 0
pixmap = Null
GCCollect
EndFunction
Function Spawn(x:Int, y:Int)
For Local p:TParticle = EachIn Particles
If p.Status = STATUS_DEAD
p.X = x
p.Y = y
p.XDir = Rnd(-0.1, 0.1)
p.YDir = Rnd(-0.1, 0.1)
p.R = Rand(32, 255)
p.G = Rand(32, 255)
p.B = Rand(32, 255)
p.Size = Rnd(0.1, 0.5)
p.Alpha = 1.0
p.Status = STATUS_LIVE
LiveCount :+ 1
Exit
EndIf
Next
EndFunction
Function RenderLive()
For Local p:TParticle = EachIn Particles
p.Render()
Next
EndFunction
'-------------------------------------
Field X:Float, Y:Float
Field XDir:Float, YDir:Float
Field R:Byte, G:Byte, B:Byte
Field Size:Float
Field Alpha:Float
Field Status:Byte
Method Render()
If Status = STATUS_LIVE
SetColor R, G, B
SetAlpha Alpha
X :+ XDir
Y :+ YDir
SetScale Size, Size
DrawImage ParticleImage, X, Y
Alpha :- 0.00005
Local Dead:Int = False
If Alpha <= 0.0 Then Dead = True
If X < 0 Or X > ScreenWidth Then Dead = True
If Y < 0 Or Y > ScreenHeight Then Dead = True
If Dead
Status = STATUS_DEAD
LiveCount :- 1
EndIf
EndIf
EndMethod
EndType
Function CreateSprite:TImage()
Local size:Int = 64
Local img:TImage = CreateImage(size, size, 1, DYNAMICIMAGE|MASKEDIMAGE)
SetBlend SOLIDBLEND
SetColor 255, 255, 255
DrawOval 0, 0, Size, Size
GrabImage(img, 0, 0)
Return img
EndFunction
List and real-time particle creation / deletion:
'Particle System Test
'List and real-time particle creation / deletion
SuperStrict
Framework BRL.GLMax2D
'Framework BRL.D3D7Max2D
Import BRL.Random
Import BRL.PNGLoader
Global ScreenWidth:Int = 800
Global ScreenHeight:Int = 600
Global MaxParticles:Int = 2000
Global SpriteURL:String = "c:\program files\blitzmax\samples\birdie\games\tiledrop\media\part.png"
'Note: A sprite will automatically be created if one is not found at the url above
Graphics ScreenWidth, ScreenHeight, 32
TParticle.Init MaxParticles, SpriteURL
Local Renders:Int, FPS:Int
Local CurrentMS:Int, OldMS:Int
Local MemAlloced:Int = GCMemAlloced()
SetBlend ALPHABLEND
MoveMouse ScreenWidth / 2, ScreenHeight / 2
While Not KeyHit(KEY_ESCAPE)
Cls
TParticle.Spawn MouseX(), MouseY()
TParticle.RenderLive
If KeyHit(KEY_M) Then MemAlloced = GCMemAlloced()
SetColor 255, 255, 255
SetAlpha 1.0
SetScale 1.0, 1.0
Renders :+ 1
CurrentMS = MilliSecs()
If (CurrentMS - OldMS) >= 1000
OldMS = CurrentMS
FPS = Renders
Renders = 0
EndIf
DrawText FPS + " FPS", 10, 10
DrawText "Memory: " + MemAlloced + " bytes", 10, 30
DrawText "Live particles: " + TParticle.LiveCount, 10, 70
DrawText "Press M to refresh memory useage value.", 10, ScreenHeight - 30
Flip 0
Wend
End
Type TParticle
Const STATUS_DEAD:Int = 0
Const STATUS_LIVE:Int = 1
Global MaxParticles:Int
Global Particles:TList
Global LiveCount:Int
Global ParticleImage:TImage
Function Init(qty:Int, img_url:String= "")
Local pixmap:TPixmap = LoadPixmap(img_url)
If pixmap Then
Pixmap = ResizePixmap(pixmap, 64, 64)
ParticleImage = LoadImage(pixmap)
Else
ParticleImage = createSprite()
EndIf
MaxParticles = qty
Particles = New TList
LiveCount = 0
pixmap = Null
GCCollect
EndFunction
Function Spawn(x:Int, y:Int)
If LiveCount < MaxParticles
Local p:TParticle = New TParticle
p.X = x
p.Y = y
p.XDir = Rnd(-0.1, 0.1)
p.YDir = Rnd(-0.1, 0.1)
p.R = Rand(32, 255)
p.G = Rand(32, 255)
p.B = Rand(32, 255)
p.Size = Rnd(0.1, 0.5)
p.Alpha = 1.0
Particles.AddLast p
LiveCount :+ 1
EndIf
EndFunction
Function RenderLive()
For Local p:TParticle = EachIn Particles
If p.Render() = STATUS_DEAD
Particles.Remove p
LiveCount :- 1
EndIf
Next
EndFunction
'-------------------------------------
Field X:Float, Y:Float
Field XDir:Float, YDir:Float
Field R:Byte, G:Byte, B:Byte
Field Size:Float
Field Alpha:Float
Method Render:Int()
SetColor R, G, B
SetAlpha Alpha
X :+ XDir
Y :+ YDir
SetScale Size, Size
DrawImage ParticleImage, X, Y
Alpha :- 0.00005
Local Dead:Int = False
If Alpha <= 0.0 Then Dead = True
If X < 0 Or X > ScreenWidth Then Dead = True
If Y < 0 Or Y > ScreenHeight Then Dead = True
If Dead Then Return STATUS_DEAD Else Return STATUS_LIVE
EndMethod
EndType
Function CreateSprite:TImage()
Local size:Int = 64
Local img:TImage = CreateImage(size, size, 1, DYNAMICIMAGE|MASKEDIMAGE)
SetBlend SOLIDBLEND
SetColor 255, 255, 255
DrawOval 0, 0, Size, Size
GrabImage(img, 0, 0)
Return img
EndFunction
Particle pool list and live particle list:
'Particle System Test
'Particle pool list and live particle list
SuperStrict
Framework BRL.GLMax2D
'Framework BRL.D3D7Max2D
Import BRL.Random
Import BRL.PNGLoader
Global ScreenWidth:Int = 800
Global ScreenHeight:Int = 600
Global MaxParticles:Int = 2000
Global SpriteURL:String = "c:\program files\blitzmax\samples\birdie\games\tiledrop\media\part.png"
'Note: A sprite will automatically be created if one is not found at the url above
Graphics ScreenWidth, ScreenHeight, 32
TParticle.Init MaxParticles, SpriteURL
Local Renders:Int, FPS:Int
Local CurrentMS:Int, OldMS:Int
Local MemAlloced:Int = GCMemAlloced()
SetBlend ALPHABLEND
MoveMouse ScreenWidth / 2, ScreenHeight / 2
While Not KeyHit(KEY_ESCAPE)
Cls
TParticle.Spawn MouseX(), MouseY()
TParticle.RenderLive
If KeyHit(KEY_M) Then MemAlloced = GCMemAlloced()
SetColor 255, 255, 255
SetAlpha 1.0
SetScale 1.0, 1.0
Renders :+ 1
CurrentMS = MilliSecs()
If (CurrentMS - OldMS) >= 1000
OldMS = CurrentMS
FPS = Renders
Renders = 0
EndIf
DrawText FPS + " FPS", 10, 10
DrawText "Memory: " + MemAlloced + " bytes", 10, 30
DrawText "Live particles: " + TParticle.LiveCount, 10, 70
DrawText "Press M to refresh memory useage value.", 10, ScreenHeight - 30
Flip 0
Wend
End
Type TParticle
Const STATUS_DEAD:Int = 0
Const STATUS_LIVE:Int = 1
Global ParticlePool:TList
Global LiveParticles:TList
Global LiveCount:Int
Global ParticleImage:TImage
Function Init(qty:Int, img_url:String= "")
Local pixmap:TPixmap = LoadPixmap(img_url)
If pixmap Then
Pixmap = ResizePixmap(pixmap, 64, 64)
ParticleImage = LoadImage(pixmap)
Else
ParticleImage = createSprite()
EndIf
ParticlePool = New TList
For Local n:Int = 1 To qty
Local p:TParticle = New TParticle
ParticlePool.AddLast p
Next
LiveParticles = New TList
LiveCount = 0
pixmap = Null
GCCollect
EndFunction
Function Spawn(x:Int, y:Int)
Local p:TParticle = Null
If Not(ParticlePool.IsEmpty())
p = TParticle(ParticlePool.RemoveFirst())
p.X = x
p.Y = y
p.XDir = Rnd(-0.1, 0.1)
p.YDir = Rnd(-0.1, 0.1)
p.R = Rand(32, 255)
p.G = Rand(32, 255)
p.B = Rand(32, 255)
p.Size = Rnd(0.1, 0.5)
p.Alpha = 1.0
LiveParticles.AddLast p
LiveCount :+ 1
EndIf
EndFunction
Function RenderLive()
For Local p:TParticle = EachIn LiveParticles
If p.Render() = STATUS_DEAD
LiveParticles.Remove p
ParticlePool.AddLast p
LiveCount :- 1
EndIf
Next
EndFunction
'-------------------------------------
Field X:Float, Y:Float
Field XDir:Float, YDir:Float
Field R:Byte, G:Byte, B:Byte
Field Size:Float
Field Alpha:Float
Method Render:Int()
SetColor R, G, B
SetAlpha Alpha
X :+ XDir
Y :+ YDir
SetScale Size, Size
DrawImage ParticleImage, X, Y
Alpha :- 0.00005
Local Dead:Int = False
If Alpha <= 0.0 Then Dead = True
If X < 0 Or X > ScreenWidth Then Dead = True
If Y < 0 Or Y > ScreenHeight Then Dead = True
If Dead Then Return STATUS_DEAD Else Return STATUS_LIVE
EndMethod
EndType
Function CreateSprite:TImage()
Local size:Int = 64
Local img:TImage = CreateImage(size, size, 1, DYNAMICIMAGE|MASKEDIMAGE)
SetBlend SOLIDBLEND
SetColor 255, 255, 255
DrawOval 0, 0, Size, Size
GrabImage(img, 0, 0)
Return img
EndFunction
'Particle pool list and live particle list
'(Incorporating dmaz's non-BRL list logic):
'Particle System Test
'Particle pool list and live particle list
'(Incorporating dmaz's non-BRL list logic)
SuperStrict
Framework BRL.GLMax2D
'Framework BRL.D3D7Max2D
Import BRL.Random
Import BRL.PNGLoader
Global ScreenWidth:Int = 800
Global ScreenHeight:Int = 600
Global MaxParticles:Int = 2000
Global SpriteURL:String = "c:\program files\blitzmax\samples\birdie\games\tiledrop\media\part.png"
'Note: A sprite will automatically be created if one is not found at the url above
Graphics ScreenWidth, ScreenHeight, 32
TParticle.Init MaxParticles, SpriteURL
Local Renders:Int, FPS:Int
Local CurrentMS:Int, OldMS:Int
Local MemAlloced:Int = GCMemAlloced()
SetBlend ALPHABLEND
MoveMouse ScreenWidth / 2, ScreenHeight / 2
While Not KeyHit(KEY_ESCAPE)
Cls
TParticle.Spawn MouseX(), MouseY()
TParticle.RenderLive
If KeyHit(KEY_M) Then MemAlloced = GCMemAlloced()
SetColor 255, 255, 255
SetAlpha 1.0
SetScale 1.0, 1.0
Renders :+ 1
CurrentMS = MilliSecs()
If (CurrentMS - OldMS) >= 1000
OldMS = CurrentMS
FPS = Renders
Renders = 0
EndIf
DrawText FPS + " FPS", 10, 10
DrawText "Memory: " + MemAlloced + " bytes", 10, 30
DrawText "Live particles: " + TParticle.LiveCount, 10, 70
DrawText "Press M to refresh memory useage value.", 10, ScreenHeight - 30
Flip 0
Wend
End
Type TParticle
Const STATUS_DEAD:Int = 0
Const STATUS_LIVE:Int = 1
Global ParticlePool:TParticle
Global LiveParticles:TParticle
Global LiveCount:Int
Global ParticleImage:TImage
Function Init(qty:Int, img_url:String= "")
Local pixmap:TPixmap = LoadPixmap(img_url)
If pixmap Then
Pixmap = ResizePixmap(pixmap, 64, 64)
ParticleImage = LoadImage(pixmap)
Else
ParticleImage = createSprite()
EndIf
For Local n:Int = 1 To qty
Local p:TParticle = New TParticle
p.NextParticle = ParticlePool
ParticlePool = p
Next
LiveCount = 0
pixmap = Null
GCCollect
EndFunction
Function Spawn(x:Int, y:Int)
Local p:TParticle = Null
If ParticlePool <> Null
p = ParticlePool
ParticlePool = p.NextParticle
p.X = x
p.Y = y
p.XDir = Rnd(-0.1, 0.1)
p.YDir = Rnd(-0.1, 0.1)
p.R = Rand(32, 255)
p.G = Rand(32, 255)
p.B = Rand(32, 255)
p.Size = Rnd(0.1, 0.5)
p.Alpha = 1.0
p.NextParticle = LiveParticles
LiveParticles = p
LiveCount :+ 1
EndIf
EndFunction
Function RenderLive()
Local lp:TParticle
Local np:TParticle
Local p:TParticle = LiveParticles
While p
np = p.NextParticle
If p.Render() = STATUS_DEAD
If lp
lp.NextParticle = p.NextParticle
Else
LiveParticles = p.NextParticle
EndIf
p.NextParticle = ParticlePool
ParticlePool = p
LiveCount :- 1
Else
lp = p
EndIf
p = np
Wend
EndFunction
'-------------------------------------
Field X:Float, Y:Float
Field XDir:Float, YDir:Float
Field R:Byte, G:Byte, B:Byte
Field Size:Float
Field Alpha:Float
Field NextParticle:TParticle
Method Render:Int()
SetColor R, G, B
SetAlpha Alpha
X :+ XDir
Y :+ YDir
SetScale Size, Size
DrawImage ParticleImage, X, Y
Alpha :- 0.00005
Local Dead:Int = False
If Alpha <= 0.0 Then Dead = True
If X < 0 Or X > ScreenWidth Then Dead = True
If Y < 0 Or Y > ScreenHeight Then Dead = True
If Dead Then Return STATUS_DEAD Else Return STATUS_LIVE
EndMethod
EndType
Function CreateSprite:TImage()
Local size:Int = 64
Local img:TImage = CreateImage(size, size, 1, DYNAMICIMAGE|MASKEDIMAGE)
SetBlend SOLIDBLEND
SetColor 255, 255, 255
DrawOval 0, 0, Size, Size
GrabImage(img, 0, 0)
Return img
EndFunction