Particle System

BlitzMax Forums/BlitzMax Programming/Particle System

SSS(Posted 2007) [#1]
Hi everyone! (Full code at the bottom of the post)

I started work on an RTS a little while ago and decided that it was time to make a particle system for it. Now, I've never actually made a particle system so this was a first but I kind of like the design. So, I've decided to release it. I only started it an hour or so ago so don't expect much; but that's kind of the philosophy. It's meant to be as modular as possible to allow for any modifications that you want.

The way it works is through "modifiers". Particles themselves have nothing associated with them. Instead they are acted upon by modifiers that are all user defined. They can hold any kind of data that you'd like them to hold through the use of a "Data" type. Furthermore user defined emitters govern the creation of the particles themselves.

Anyway, code might make it slightly easier to see so here is the underlying structure:



Then, in the main loop,
Graphics 800,600

While Not KeyDown(KEY_ESCAPE)
	Cls
	TModifier.UpdateAll()
	TEmitter.UpdateAll()
	Flip
Wend


Clearly though, this won't do anything at all! So, to make it do something useful. To start we need to add some modifiers and emitters. Lets start with making the particles able to draw and move. Lets also add an emitter that will emit particles randomly in every direction.



Then a random emitter would have to be added to the main loop. It would become,
Local em:TRandomEmitter = New TRandomEmitter
em.x = 400
em.y = 300
em.rate = 5
While Not KeyDown(KEY_ESCAPE)
	Cls
	TModifier.UpdateAll()
	TEmitter.UpdateAll()
	Flip
Wend


To see how easy it is to add new modifiers let us make it so that the particles fade out. This requires four modifications:

1) The introduction of a data type to hold the alpha of the particles

2) The introduction of a type to adjust the alpha

3) Modification to the drawing type to draw with alpha

4) The addition of the fade type in the emitter

The base types look like,
Type TAlpha Extends TData
	Field alpha#
	
	Method New()
		name$ = "alpha"
		alpha = 1.0
	End Method
	
	Function Create:TAlpha(alpha#)
		Local p:TAlpha =New TAlpha
		p.alpha = alpha
		Return p
	End Function
End Type

Type TFade Extends TModifier
	Method Update(p:TParticle)
		Local alpha:TAlpha = TAlpha(p.Get("alpha"))
		alpha.alpha:-0.01
		If alpha.alpha<0 Then p.alive = False
	End Method
	
	Method SetData(p:TParticle)
		p.AddData(New TAlpha)
	End Method
	
	Method Lock()
	End Method
	
	Method Unlock()
	End Method
End Type


and the updated draw type and emitter type look like,
Type TRandomEmitter Extends TEmitter
	Global drawing:TDrawing = New TDrawing
	Global mover:TMove = New TMove
	Global culler:TCull = New TCull
	Global fader:TFade = New TFade


	Method Emit()
		Local p:TParticle = New TParticle
		p.AddData(TPosition.Create(x,y))
		p.AddData(TVelocity.Create(Rnd(4)-2,Rnd(4)-2))
		p.AddData(TColor.Create(Rand(255),Rand(255),Rand(255)))
		p.AddData(New TAlpha)
		fader.AddParticle(p)
		drawing.AddParticle(p)
		mover.AddParticle(p)
		culler.AddParticle(p)
	End Method
End Type

Type TDrawing Extends TModifier
	Field blendmode
	
	Method Update(p:TParticle)
		Local pos:TPosition = TPosition(p.Get("position"))
		Local col:TColor = TColor(p.Get("color"))
		Local alpha:TAlpha = TAlpha(p.Get("alpha"))
		If Not alpha = Null
			SetAlpha alpha.alpha
		EndIf
		If Not col = Null
			SetColor col.r,col.g,col.b
		EndIf
		DrawOval pos.x#-2,pos.y#-2,4,4
		SetColor 255,255,255
		SetAlpha 1
	End Method
	
	Method SetData(p:TParticle)
		p.AddData(New TPosition)
	End Method
	
	Method Lock()
		blendmode = GetBlend()
		SetBlend ALPHABLEND
	End Method
	
	Method Unlock()
		SetBlend blendmode
	End Method
End Type 


Here's all the code in one place ready to be run!


Anyway, I hope someone finds this in some way useful and I'd love to hear comments/critiques on the design.


SSS(Posted 2007) [#2]
If anyone actually decides they might want to use this then post here and I'll write up some more formal documentation about the addition of new modifiers etc... The basic theory is that you should never have to touch any of the underlying code (that which is in the first box).