This is a collection about 40 functions you can use to create and manage 2D particle systems. I was bored today and I have several 2D games in mind I'd like to get started on, so I took the last couple hours to get this done.
Here's the include file:
Type Particle
Img as Integer
Spr as Integer
X as Float
Y as Float
VelX as Float
VelY as Float
AccX as Float
AccY as Float
Scale as Float
Ang as Float
StartAlpha as DWORD
EndAlpha as DWORD
StartColor as DWORD
EndColor as DWORD
StartScale as Float
EndScale as Float
StartSpin as Float
EndSpin as Float
LifeTime as Integer
AccumTime as Integer
EndType
Type ParticleEmitter
IsActive as Boolean
Texture as Integer
Spr as Integer
EmitTime as Integer
AccumTime as Integer
NumParticles as Integer
InitVel as Float
MinAng as Float
MaxAng as Float
GravityX as Float
GravityY as Float
Life as Float
X as Float
Y as Float
StartColor as DWORD
EndColor as DWORD
StartAlpha as DWORD
EndAlpha as DWORD
StartScale as Float
EndScale as Float
StartSpin as Float
EndSpin as Float
EndType
Function InitParticles()
Dim _Emitters() as ParticleEmitter
Dim _Particles() as Particle
EndFunction
Function MakeParticleEmitter(X as Float, Y as Float, Life as Float, Vel as Float, Rate as Float, GravityX as Float, GravityY as Float, Texture as Integer)
Array Insert At Bottom _Emitters()
ID = Array Count(_Emitters())
_Emitters(ID).Spr = Find Free Sprite()
Sprite _Emitters(ID).Spr, -1000, -1000, Texture
_Emitters(ID).X = X
_Emitters(ID).Y = Y
_Emitters(ID).InitVel = Vel
_Emitters(ID).EmitTime = Rate
_Emitters(ID).Life = Life
_Emitters(ID).GravityX = GravityX
_Emitters(ID).GravityY = GravityY
_Emitters(ID).Texture = Texture
_Emitters(ID).NumParticles = 1
_Emitters(ID).StartColor = RGB(255, 255, 255)
_Emitters(ID).EndColor = RGB(255, 255, 255)
_Emitters(ID).StartAlpha = 255
_Emitters(ID).EndAlpha = 0
_Emitters(ID).StartScale = 100.0
_Emitters(ID).EndScale = 100.0
_Emitters(ID).StartSpin = 0.0
_Emitters(ID).EndSpin = 0.0
_Emitters(ID).MinAng = 0.0
_Emitters(ID).MaxAng = 360.0
_Emitters(ID).IsActive = 1
EndFunction ID
Function DeleteParticleEmitter(ID)
Array Delete Element _Emitters(), ID
EndFunction
Function GetParticleCount()
TEMP = Array Count(_Particles())
EndFunction TEMP
Function GetEmitterCount()
TEMP = Array Count(_Emitters())
EndFunction TEMP
Function GetEmitterActive(ID)
TEMP = _Emitters(ID).IsActive
EndFunction TEMP
Function SetEmitterActive(ID, Active)
_Emitters(ID).IsActive = Active
EndFunction
Function GetEmitterPositionX(ID)
TEMP# = _Emitters(ID).X
EndFunction TEMP#
Function GetEmitterPositionY(ID)
TEMP# = _Emitters(ID).Y
EndFunction TEMP#
Function SetEmitterPosition(ID, X as Float, Y as Float)
_Emitters(ID).X = X
_Emitters(ID).Y = Y
EndFunction
Function GetEmitterTexture(ID)
TEMP = _Emitters(ID).Texture
EndFunction TEMP
Function SetEmitterTexture(ID, Texture)
_Emitters(ID).Texture = Texture
EndFunction
Function GetEmitterMinAng(ID)
TEMP# = _Emitters(ID).MinAng
EndFunction TEMP#
Function GetEmitterMaxAng(ID)
TEMP# = _Emitters(ID).MaxAng
EndFunction TEMP#
Function SetEmitterMinAng(ID, Ang as Float)
_Emitters(ID).MinAng = Ang
EndFunction
Function SetEmitterMaxAng(ID, Ang as Float)
_Emitters(ID).MaxAng = Ang
EndFunction
Function GetEmitterLife(ID)
TEMP# = _Emitters(ID).Life
EndFunction TEMP#
Function SetEmitterLife(ID, Life as Float)
_Emitters(ID).Life = Life
EndFunction
Function GetEmitterVelocity(ID)
TEMP# = _Emitters(ID).InitVel
EndFunction TEMP#
Function SetEmitterVelocity(ID, InitVel as Float)
_Emitters(ID).InitVel = InitVel
EndFunction
Function GetEmitterGravityX(ID)
TEMP# = _Emitters(ID).GravityX
EndFunction TEMP#
Function GetEmitterGravityY(ID)
TEMP# = _Emitters(ID).GravityY
EndFunction TEMP#
Function SetEmitterGravity(ID, GravityX as Float, GravityY as Float)
_Emitters(ID).GravityX = GravityX
_Emitters(ID).GravityY = GravityY
EndFunction
Function GetEmitterRate(ID)
TEMP# = _Emitters(ID).EmitTime
EndFunction TEMP#
Function SetEmitterRate(ID, Rate as Float)
_Emitters(ID).EmitTime = Rate
EndFunction
Function GetEmitterNumParticles(ID)
TEMP = _Emitters(ID).NumParticles
EndFunction
Function SetEmitterNumParticles(ID, Num)
_Emitters(ID).NumParticles = Num
EndFunction
Function GetEmitterStartColor(ID)
TEMP = _Emitters(ID).StartColor
EndFunction TEMP
Function GetEmitterEndColor(ID)
TEMP = _Emitters(ID).EndColor
EndFunction
Function SetEmitterColor(ID, StartColor, EndColor)
_Emitters(ID).StartColor = StartColor
_Emitters(ID).EndColor = EndColor
EndFunction
Function GetEmitterStartAlpha(ID)
TEMP = _Emitters(ID).StartAlpha
EndFunction TEMP
Function GetEmitterEndAlpha(ID)
TEMP = _Emitters(ID).EndAlpha
EndFunction TEMP
Function SetEmitterAlpha(ID, StartAlpha, EndAlpha)
_Emitters(ID).StartAlpha = StartAlpha
_Emitters(ID).EndAlpha = EndAlpha
EndFunction
Function GetEmitterStartScale(ID)
TEMP# = _Emitters(ID).StartScale
EndFunction TEMP#
Function GetEmitterEndScale(ID)
TEMP# = _Emitters(ID).EndScale
EndFunction TEMP#
Function SetEmitterScale(ID, StartScale as Float, EndScale as Float)
_Emitters(ID).StartScale = StartScale
_Emitters(ID).EndScale = EndScale
EndFunction
Function GetEmitterStartSpin(ID)
TEMP# = _Emitters(ID).StartSpin
EndFunction TEMP#
Function GetEmitterEndSpin(ID)
TEMP# = _Emitters(ID).EndSpin
EndFunction TEMP#
Function SetEmitterSpin(ID, StartSpin as Float, EndSpin as Float)
_Emitters(ID).StartSpin = StartSpin
_Emitters(ID).EndSpin = EndSpin
EndFunction
Function UpdateParticles(TimeStep as Float)
//Update particle spawning/emitting.
For I = 0 to Array Count(_Emitters())
If _Emitters(I).IsActive
Inc _Emitters(I).AccumTime, TimeStep
If _Emitters(I).AccumTime > _Emitters(I).EmitTime
_Emitters(I).AccumTime = 0
Ang as Float
For N = 1 to _Emitters(I).NumParticles
Ang = Rnd(_Emitters(I).MaxAng - _Emitters(I).MinAng) + _Emitters(I).MinAng
SpawnParticle(_Emitters(I).Spr, _Emitters(I).Texture, _Emitters(I).X, _Emitters(I).Y, Sin(Ang) * _Emitters(I).InitVel, Cos(Ang) * _Emitters(I).InitVel, _Emitters(I).GravityX, _Emitters(I).GravityY, _Emitters(I).Life, _Emitters(I).StartColor, _Emitters(I).EndColor, _Emitters(I).StartAlpha, _Emitters(I).EndAlpha, _Emitters(I).StartScale, _Emitters(I).EndScale, _Emitters(I).StartSpin, _Emitters(I).EndSpin)
Next N
EndIf
EndIf
Next I
//Update particle movement.
For I = 0 to Array Count(_Particles())
Inc _Particles(I).VelX, TBVal(TimeStep, _Particles(I).AccX)
Inc _Particles(I).VelY, TBVal(TimeStep, _Particles(I).AccY)
Inc _Particles(I).X, TBVal(TimeStep, _Particles(I).VelX)
Inc _Particles(I).Y, TBVal(TimeStep, _Particles(I).VelY)
Offset Sprite _Particles(I).Spr, Image Width(_Particles(I).Img) / 2, Image Height(_Particles(I).Img) / 2
L# = _Particles(I).AccumTime
T# = _Particles(I).LifeTime
A = LnInterp(_Particles(I).StartAlpha, _Particles(I).EndAlpha, L# / T#)
Set Sprite Alpha _Particles(I).Spr, A
Col = LnInterpCol(_Particles(I).StartColor, _Particles(I).EndColor, L# / T#)
Set Sprite Diffuse _Particles(I).Spr, RGBR(Col), RGBG(Col), RGBB(Col)
Scale Sprite _Particles(I).Spr, LnInterp(_Particles(I).StartScale, _Particles(I).EndScale, (L# / T#))
Inc _Particles(I).Ang, TBVal(TimeStep, LnInterp(_Particles(I).StartSpin, _Particles(I).EndSpin, L# / T#))
Rotate Sprite _Particles(I).Spr, _Particles(I).Ang
Paste Sprite _Particles(I).Spr, _Particles(I).X, _Particles(I).Y
Inc _Particles(I).AccumTime, TimeStep
If _Particles(I).AccumTime > _Particles(I).LifeTime
Array Delete Element _Particles(), I
Else
If _Particles(I).X + (Image Width(_Particles(I).Img) / 2) < 0 or _Particles(I).X - (Image Width(_Particles(I).Img) / 2) > Screen Width() or _Particles(I).Y + (Image Height(_Particles(I).Img) / 2) < 0 or _Particles(I).Y - (Image Height(_Particles(I).Img) / 2) > Screen Height()
Array Delete Element _Particles(), I
EndIf
EndIf
Next I
EndFunction
Function SpawnParticle(Spr, Img, X as Float, Y as Float, VelX as Float, VelY as Float, AccX as Float, AccY as Float, LifeTime as Integer, StartCol, EndCol, StartAlpha, EndAlpha, StartScale as Float, EndScale as Float, StartSpin as Float, EndSpin as Float)
//Add an element to the _Particles() array.
Array Insert At Bottom _Particles()
ID = Array Count(_Particles())
_Particles(ID).Img = Img
_Particles(ID).Spr = Spr
_Particles(ID).X = X
_Particles(ID).Y = Y
_Particles(ID).VelX = VelX
_Particles(ID).VelY = VelY
_Particles(ID).AccX = AccX
_Particles(ID).AccY = AccY
_Particles(ID).LifeTime = LifeTime
_Particles(ID).StartColor = StartCol
_Particles(ID).EndColor = EndCol
_Particles(ID).StartAlpha = StartAlpha
_Particles(ID).EndAlpha = EndAlpha
_Particles(ID).StartScale = StartScale
_Particles(ID).EndScale = EndScale
_Particles(ID).StartSpin = StartSpin
_Particles(ID).EndSpin = EndSpin
EndFunction ID
Function TBVal(TimeStep as Float, Value as Float)
TEMP# = TimeStep * (Value / 15)
EndFunction TEMP#
Function LnInterpCol(Col1 as DWORD, Col2 as DWORD, Percent as Float)
R1 as Float : R1 = RGBR(Col1)
G1 as Float : G1 = RGBG(Col1)
B1 as Float : B1 = RGBB(Col1)
R2 as Float : R2 = RGBR(Col2)
G2 as Float : G2 = RGBG(Col2)
B2 as Float : B2 = RGBB(Col2)
NewR as Float : NewR = R1 + ((R2 - R1) * Percent)
NewG as Float : NewG = G1 + ((G2 - G1) * Percent)
NewB as Float : NewB = B1 + ((B2 - B1) * Percent)
NewCol as DWORD : NewCol = RGB(NewR, NewG, NewB)
EndFunction NewCol
Function LnInterp(X1 as Float, X2 as Float, Percent as Float)
NewX as Float
NewX = X1 + ((X2 - X1) * Percent)
EndFunction NewX
Here's a rundown of the properties of the particle systems, however I'm pretty bad at explaining things so if you have any questions please ask:
Texture: The emitter's texture is the image used for its particles.
Delay: The emitters' delay is the amount of time between particle emissions, i.e. if you set it to 15, it will emit a particle every 15 ms, or 60 times per second.
Life: The length of time in ms that the each particle of the emitter will be alive/active.
Gravity: The amount of acceleration applied to the emitter's particles.
Initial Velocity: The initial velocity of the emitter's particles.
Number of Particles: The number of particles emitted each time an emission takes place. That is, if you set 'Delay' to 15, the emitter will emit particles every 15 ms, and if you set Number of Particles to 5, it will emit 5 particles every 15 ms.
Color: The emitter has two colors: start color and end color. The start color is the color of the particles when they're first emitted, and the end color is the color of the particle at the end of its life. If you set start color to red and the end to blue, it will slowly fade from red to blue throughout the particle's life.
Alpha: The alpha works the same way as the color, you set a start alpha and an end alpha and each particle fades from the start alpha to the end alpha.
Scale: The scale also works the same way as the color, you specify a start scale and an end scale, and the particle will slowly grow/shrink.
Spin: The amount that each particle is rotated each frame. This works the same way as the scale, you set a start spin and an end spin, and the spinning will speed up/slow down during the particle's life.
Emitter Angle: The emitter's angle has two properties: minimum angle, and maximum angle. The angle decides the angle at which particles are emitted. If you set the start angle to 90.0 and the end angle to 180.0, then each particle will be emitted at a random angle between 90 and 180. You could set both the start and end angles to the same value to have every particle emitted at the same angle.
I will post the functions with explanations if anybody requests it, but for now you can take a look at the '2D Particles' example below:
[Demo]
which includes the example source. Basically you call InitParticles() before any other particle functions. Then you call UpdateParticles() in your main loop, however you'll notice it takes a function 'TimeStep'. This is the amount of time your main loop takes. You can do this by either timing the main loop, like you do for timer-based movement, or you can lock your framerate at 60 and set it to 15. To make a particle emitter you use MakeParticleEmitter(), the parameters are explained in the code, and to set other properties you can use the other various functions, most of which should also be explained in the code.
If you have any suggestions or questions don't hesitate to ask.