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:
Array and status-related rendering:
List and real-time particle creation / deletion:
Particle pool list and live particle list:
'Particle pool list and live particle list
'(Incorporating dmaz's non-BRL list logic):
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