Code archives/Graphics/Particles!

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

Download source code

Particles! by matibee2009
A simple 2d particle system complete with a useful (though a little cludged together) editor written in MaxGUI. There's a collection of particle parameters such as alpha,red,green,blue,rotation,scale & weight, and 'factor' values that adjusts each parameter over time.

eg. alpha = 1 and alphafactor -1 will fade alpha from 1 to 0 over one second.
alpha = 1 and alphafactor = -0.5 will fade it over two seconds.

Particles are tied to an emitter, which releases particles in 'Bursts' [doBurst(x,y)]. Emitter parameters include random velocity range and number of particles per burst. To maintain consistant results over different frame rates the bursts are limited to 20 per second. So the editor results (timed to run at 20fps) will be the same as your game results no matter how often you call DoBurst. If you want to override the 20fps limit (useful if you're interpolating the emitter position during one frame), it's as simple as DoBurst(x,y,False).

Screenshot: www.matibee.co.uk/temp/particles.jpg

(I'm not sure how to use the code arc's, so this is an experiment!)...

The editor code..


The sample code..


The 'fire.txt' emitter used in the sample
point_weight=1.00000000
point_scale=1.00000000
point_scalefactor=2.00000000
point_rotationfactor=720.000000
point_velocity_min=-100.000000
point_velocity_max=100.000000
point_red=1.00000000
point_redfactor=1.00000000
point_green=1.00000000
point_greenfactor=-1.00000000
point_blue=0.000000000
point_bluefactor=0.000000000
point_alpha=0.500000000
point_alphafactor=-0.500000000
emitter_particles_per_burst=20
xhandle=8
yhandle=8
image=Particle1.tga


some other emitters
point_weight=10.0000000
point_scale=0.200000003
point_scalefactor=1.60000002
point_rotationfactor=600.000000
point_velocity_min=-350.000000
point_velocity_max=350.000000
point_red=1.00000000
point_redfactor=0.000000000
point_green=0.000000000
point_greenfactor=1.00000000
point_blue=0.000000000
point_bluefactor=1.00000000
point_alpha=1.00000000
point_alphafactor=-1.00000000
emitter_particles_per_burst=40
xhandle=8
yhandle=8
image=Particle1.tga

point_weight=40.0000000
point_scale=1.00000000
point_scalefactor=-0.200000003
point_rotationfactor=0.000000000
point_velocity_min=1.00000000
point_velocity_max=80.0000000
point_red=1.00000000
point_redfactor=0.000000000
point_green=0.000000000
point_greenfactor=1.00000000
point_blue=1.00000000
point_bluefactor=0.000000000
point_alpha=1.00000000
point_alphafactor=-1.00000000
emitter_particles_per_burst=2
xhandle=8
yhandle=8
image=Particle1.tga

point_weight=10.0000000
point_scale=1.00000000
point_scalefactor=-0.200000003
point_rotationfactor=720.000000
point_velocity_min=-1.000000000
point_velocity_max=30.0000000
point_red=1.00000000
point_redfactor=0.000000000
point_green=0.500000000
point_greenfactor=-0.500000000
point_blue=0.000000000
point_bluefactor=0.800000012
point_alpha=1.00000000
point_alphafactor=-0.600000024
emitter_particles_per_burst=2
xhandle=-2
yhandle=-2
image=Particle1.tga


My .tga file can be found here
www.matibee.co.uk/temp/Particle1.tga

It's not the most thorough particle system in the world, but along with the editor, it might serve as a useful learning aid or start point to improve upon.

Cheers
Matt
Const MAX_PARTICLES_PER_EMITTER%	= 600


Type Particle
	Field m_fAge:Float
	Field m_fScale:Float
	Field m_fRotation:Float
	Field m_fVelocityX:Float
	Field m_fVelocityY:Float
	Field m_fRed:Float
	Field m_fBlue:Float
	Field m_fGreen:Float
	Field m_fAlpha:Float
	Field m_fX:Float
	Field m_fY:Float
End Type


Type ParticleEmitter

	Field m_freeParticles:TList
	Field m_liveParticles:TList 
	
	Field m_baseParticle:Particle
	
	Field m_fPointWeight:Float = 1.0
	Field m_fScaleFactor:Float = -0.2
	Field m_fRotationFactor:Float = 720.0
	Field m_fVelocityMin:Float = 9.0
	Field m_fVelocityMax:Float = 100.0
	Field m_fRedFactor:Float = 0.0
	Field m_fBlueFactor:Float = 0.0
	Field m_fGreenFactor:Float = 0.0
	Field m_fAlphaFactor:Float = -1.0
	
	Field m_iParticlesPerBurst:Int = 20
	
	Field m_Image:TImage
	Field m_iXHandle:Int, m_iYHandle:Int
	
	Field m_lastBurstTime:Int
	
	Function Create:ParticleEmitter( strUrl:String = "", IgnoreImage:Int = False )
		Local emitter:ParticleEmitter = New ParticleEmitter
		emitter.m_freeParticles = New TList 
		emitter.m_liveParticles = New TList 
		emitter.m_baseParticle = New Particle
		For Local t:Int = 0 To MAX_PARTICLES_PER_EMITTER - 1
			emitter.m_freeParticles.AddLast( New Particle )
		Next
		If ( Len (strUrl) )
			Local inFile:TStream = ReadFile( strUrl )
			While ( inFile And Not Eof( inFile ) )
				'Debugstop
				Local strLine:String = ReadLine( inFile )
				If ( Len(strLine) > 0 And Left( strline, 1 ) <> "'" )
					Local key:String = Left( strLine, Instr( strLine, "=" ) - 1 )
					Local value:String = Right( strLine, Len( strLine ) - Instr( strLine, "=" ) )
					If ( key = "point_weight" )
						emitter.m_fPointWeight = value.ToFloat()
					Else If ( key = "point_scalefactor" )
						emitter.m_fScaleFactor = value.ToFloat()
					Else If ( key = "point_scale" )
						emitter.m_baseParticle.m_fScale = value.ToFloat()
					Else If ( key = "point_rotationfactor" )
						emitter.m_fRotationFactor = value.ToFloat()
					Else If ( key = "point_velocity_min" )
						emitter.m_fVelocityMin = value.ToFloat()
					Else If ( key = "point_velocity_max" )
						emitter.m_fVelocityMax = value.ToFloat()
					Else If ( key = "point_redfactor" )
						emitter.m_fRedFactor = value.ToFloat()
					Else If ( key = "point_red" )
						emitter.m_baseParticle.m_fRed = value.ToFloat()
					Else If ( key = "point_greenfactor" )
						emitter.m_fGreenFactor = value.ToFloat()
					Else If ( key = "point_green" )
						emitter.m_baseParticle.m_fGreen = value.ToFloat()
					Else If ( key = "point_bluefactor" )
						emitter.m_fBlueFactor = value.ToFloat()
					Else If ( key = "point_blue" )
						emitter.m_baseParticle.m_fBlue = value.ToFloat()
					Else If ( key = "point_alphafactor" )
						emitter.m_fAlphaFactor = value.ToFloat()
					Else If ( key = "point_alpha" )
						emitter.m_baseParticle.m_fAlpha = value.ToFloat()
					Else If ( key = "emitter_particles_per_burst" )
						emitter.m_iParticlesPerBurst = value.ToInt()
					Else If ( key = "image" And Not IgnoreImage )
						emitter.m_Image = LoadImage( value, FILTEREDIMAGE )
					Else If ( key = "xhandle" )
						emitter.m_iXHandle = value.ToInt()
					Else If ( key = "yhandle" )
						emitter.m_iYHandle = value.ToInt()
					End If				
				End If
			End While
			CloseFile ( inFile )
			If emitter.m_Image SetImageHandle( emitter.m_Image, emitter.m_iXHandle, emitter.m_iYHandle )
		End If		
		Return emitter
	End Function
	
	Method Draw()
		If ( Not m_Image ) Return 
		For Local p:Particle = EachIn m_liveParticles
			SetScale p.m_fScale, p.m_fScale
			SetRotation p.m_fRotation
			SetAlpha p.m_fAlpha
			SetColor( p.m_fRed * 255.0, p.m_fGreen * 255.0, p.m_fBlue * 255.0 )
			DrawImage( m_Image, p.m_fX, p.m_fY )
		Next 
	End Method
	
	Method Update( fTime:Float )
		For Local p:Particle = EachIn m_liveParticles
			p.m_fAlpha :+ m_fAlphaFactor * fTime
			p.m_fScale :+ m_fScaleFactor * fTime
			If ( p.m_fAlpha <= 0 Or p.m_fScale <= 0 )
				m_freeParticles.AddLast( p )
				m_liveParticles.Remove( p )
			Else
				p.m_fAge :+ fTime
				p.m_fRotation :+ m_fRotationFactor * fTime
				p.m_fX :+ p.m_fVelocityX * fTime
				p.m_fY :+ p.m_fVelocityY * fTime
				p.m_fVelocityX :- m_fPointWeight * fTime
				p.m_fVelocityY :- m_fPointWeight * fTime
				p.m_fY :+ m_fPointWeight * (p.m_fAge * p.m_fAge)
				p.m_fRed :+ m_fRedFactor * fTime
				p.m_fBlue :+ m_fBlueFactor * fTime
				p.m_fGreen :+ m_fGreenFactor * fTime
			End If 
		Next 
		Assert ( m_freeParticles.Count() + m_liveParticles.Count() = MAX_PARTICLES_PER_EMITTER ) 'ensure particles don't exist in both lists!!
	End Method
	
	Method DoBurst( iX:Int, iY:Int, fpsSync:Int = True )
		If ( fpsSync )
			Local timeNow:Int = MilliSecs()
			If ( timeNow - m_lastBurstTime ) >= 20
				m_lastBurstTime = timeNow
			Else 
				Return 
			End If 
		EndIf 
		
		Local count:Int = m_iParticlesPerBurst
		For Local p:Particle = EachIn m_freeParticles
			MemCopy( p, m_baseParticle, SizeOf( Particle ) )
			p.m_fVelocityX = m_fVelocityMin + ( RndFloat() * ( m_fVelocityMax - m_fVelocityMin ) )
			p.m_fVelocityY = m_fVelocityMin + ( RndFloat() * ( m_fVelocityMax - m_fVelocityMin ) )
			p.m_fX = iX
			p.m_fY = iY
			m_liveParticles.AddLast( p )
			m_freeParticles.Remove( p )
			count :- 1
			If ( count <= 0 )
				Return
			End If
		Next 
	End Method

End Type

Comments

pmc2010
This is great. I'm having some good fun playing with it. Thank you.


christian2232010
Really nice!. I have been playing with it and I really like it, I'm going to use it in my future games, I hopefully.

I do not have MaxGui though, could you make the editor available in other ways?.


matibee2010
Sure. The full download is available here...

http://www.matibee.co.uk/wpsite/?p=15


hub2011
Very nice code.
Could you explain more matibee what's the ftime parameter into the update function ? Thanks !


matibee2011
The fTime parameter is a floating point delta time of your frame rate. ie 60 fps = 1/60 or 0.016666.


hub2011
Many thanks !


hub2011
Is there a way to set a time parameter so particules are created for example during 5 seconds (particule age ?). (i use this code to create an explosion). Thanks !


matibee2011
Is there a way to set a time parameter so particules are created for example during 5 seconds (particule age ?)


Not in this system.

Why not store the time you last called "DoBurst", then call it again 5 seconds later. This code is more concerned with the behaviour of the particles and updating them rather than controlling the emitters.


Code Archives Forum