Particle and Emitters oh my

BlitzMax Forums/BlitzMax Beginners Area/Particle and Emitters oh my

Eric(Posted 2005) [#1]
I have tried a few times to make a portable particle system...I know others have done this and I need to ask a couple of questions/Opinions.

I think of a Particle system with two distinct Classes an Emitter and a Particle. Should there be more?

Should I build an Emitter with all of the Attributes I want and then use that as the Parent to all of the particle or should I create Particles with their own distinct attributes and just let the emitter determine location and angle.

What are the most common attributes to a particle Ie. Position / Velocity / Size

What are some Ideas as far as an OOP method of building a Particle system.. Should I build a main ParticleSystem Type and then extend that into Emitters and particles.

I know these questions are really vague...but any help or Ideas would be really appreciated. I don't need code or samples just Ideas.

Thanks in advance for any help,
Eric


Who was John Galt?(Posted 2005) [#2]
*Disclaimer* I have never built a portable particle system.

"I think of a Particle system with two distinct Classes an Emitter and a Particle. Should there be more?"

This seems like a solid start. You could add another class that affects the motion of particles.

"What are the most common attributes to a particle Ie. Position / Velocity / Size"

Those seem to be the main ones - you could also have brightness, colour, rotation rate - all sorts- but these can be added in later with no hardship.

"What are some Ideas as far as an OOP method of building a Particle system.. Should I build a main ParticleSystem Type and then extend that into Emitters and particles."

One reason for doing it the way you say is if you want an emitter to be able to emit other emitters as well as particles - could make for some nice effects.

This is a bit controversial - but my recommendation is to start out with the ideas you have and build on it a bit - even if you find there are better ways of doing things and have to re-write it, it will be a good learning exercise. It's possible to get bogged down in the planning stage.


slenkar(Posted 2005) [#3]
other attributes for particles are ALPHA and BLEND
if you decrease the alpha over time then explosions look much better, and many other effects e.g. smoke


Scott Shaver(Posted 2005) [#4]
these need a lot of clean up but here:

http://www.blitzbasic.com/Community/posts.php?topic=46839

shows some simple particle stuff.


Bremer(Posted 2005) [#5]
Even though its for B3D, you might get something out of reading through the particle tutorials on my website. You should at least be able to get some ideas about how to tie emitters and particles together.


Lomat(Posted 2005) [#6]
After reading an article that i can nolonger find I implemented a simple particle system with the following classes...

* Particle - A basic particle class.
* ParticleSystem (Abstract) - Could be classified as an emitter, it responsiable for rendering and updating all of the systems particles.
* ParticleManager - Manages the particle systems.

I've put my classes into a modules for ease of reuse but i'll post the code here incase you find it of any interest.


particle.bmx
' 
' 
' Copyright (c) 2005, William Bailey <wb@...;
' All rights reserved.
' 
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are met:
' 
'     * Redistributions of source code must retain the above copyright notice,
'       this list of conditions and the following disclaimer.
'     * Redistributions in binary form must reproduce the above copyright
'       notice, this list of conditions and the following disclaimer in the
'       documentation and/or other materials provided with the distribution.
'     * Neither the name of the software nor the names of its contributors may
'       be used to endorse or promote products derived from this software
'       without specific prior written permission.
' 
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
' IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
' ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
' LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
' CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
' SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
' INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
' CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
' ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
' POSSIBILITY OF SUCH DAMAGE.
' 
' 
' 
SuperStrict

Module wb.particle

ModuleInfo "Version: 0.1"
ModuleInfo "Copyright: 2005 William Bailey <wb@...;"
ModuleInfo "Author: William Bailey"
ModuleInfo "License: BSD"

ModuleInfo "History: 17/11/2005 0.1 Release"

Import brl.linkedlist

Import wb.colorvalue
Import wb.coordinate

Include "ParticleSystem.bmx"
Include "ParticleManager.bmx"

Type Particle

	Field position:Coordinate
	Field oldPosition:Coordinate
	Field velocity:Coordinate
	Field color:ColorValue
	Field energy:Int
	Field size:Float
	Field rotation:Float
	Field rotationDelta:Float
	
	Method New ()
		position      = New Coordinate
		oldPosition   = New Coordinate
		velocity      = New Coordinate
		color         = New ColorValue
		energy        = 0
		size          = 1.0
		rotation      = 0.0
		rotationDelta = 0.0
	End Method
	
	Method update ()
		oldPosition.set(position)
		position.applyDelta(velocity)
		rotation = rotation + rotationDelta
	End Method

End Type


ParticleSystem.bmx
' 
' 
' Copyright (c) 2005, William Bailey <wb@...;
' All rights reserved.
' 
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are met:
' 
'     * Redistributions of source code must retain the above copyright notice,
'       this list of conditions and the following disclaimer.
'     * Redistributions in binary form must reproduce the above copyright
'       notice, this list of conditions and the following disclaimer in the
'       documentation and/or other materials provided with the distribution.
'     * Neither the name of the software nor the names of its contributors may
'       be used to endorse or promote products derived from this software
'       without specific prior written permission.
' 
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
' IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
' ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
' LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
' CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
' SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
' INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
' CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
' ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
' POSSIBILITY OF SUCH DAMAGE.
' 
' 
' 
Type ParticleSystem

	Field systemType:Int
	Field particles:Particle[]
	
	Method update:Int () Abstract
	Method setParticleDefaults ( p:Particle ) Abstract
	Method preRender() Abstract
	Method renderParticle (p:Particle) Abstract
	Method postRender() Abstract

	Method render ()
		preRender()
		If particles Then
			For Local i:Int = 0 To particles.length - 1
				If particles[i].energy > 0 Then
					renderParticle(particles[i])
				End If
			Next
		End If
		postRender()
	End Method
	
	Method setSystemType (value:Int)
		systemType = value
	End Method

	Method getSystemType:Int ()
		Return systemType
	End Method

End Type


ParticleManager.bmx
' 
' 
' Copyright (c) 2005, William Bailey <wb@...;
' All rights reserved.
' 
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are met:
' 
'     * Redistributions of source code must retain the above copyright notice,
'       this list of conditions and the following disclaimer.
'     * Redistributions in binary form must reproduce the above copyright
'       notice, this list of conditions and the following disclaimer in the
'       documentation and/or other materials provided with the distribution.
'     * Neither the name of the software nor the names of its contributors may
'       be used to endorse or promote products derived from this software
'       without specific prior written permission.
' 
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
' IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
' ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
' LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
' CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
' SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
' INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
' CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
' ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
' POSSIBILITY OF SUCH DAMAGE.
' 
' 
' 
Type ParticleManager

	Field system:TList

	Method New ()
		system = New TList
	End Method
	
	Method addSystem (ps:ParticleSystem, atFirstPosition:Int = 0)
		If Not system.contains(ps) Then
			If atFirstPosition Then
				system.addFirst(ps)
			Else
				system.addLast(ps)
			End If
		End If
	End Method
	
	Method removeSystem (ps:ParticleSystem)
		system.remove(ps)
	End Method
	
	Method removeSystemByType (systemType:Int)
		For Local ps:ParticleSystem = EachIn system
			If ps.getSystemType() = systemType Then
				removeSystem(ps)
			End If
		Next
	End Method
	
	Method update ()
		For Local ps:ParticleSystem = EachIn system
			If Not ps.update() Then
				removeSystem(ps)
			End If
		Next
	End Method
	
	Method render ()
		For Local ps:ParticleSystem = EachIn system
			ps.render()
		Next
	End Method
	
	Method shutDown ()
		For Local ps:ParticleSystem = EachIn system
			removeSystem(ps)
		Next
	End Method
	
	Method doesExist:Int (ps:ParticleSystem)
		Return system.contains(ps)
	End Method
	
	Method particleCount:Int ()
		Local count:Int = 0
		For Local ps:ParticleSystem = EachIn system
			If ps.particles Then
				count = count + ps.particles.length
			End If
		Next
		Return count
	End Method

End Type


colorvalue.bmx
' 
' 
' Copyright (c) 2005, William Bailey <wb@...;
' All rights reserved.
' 
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are met:
' 
'     * Redistributions of source code must retain the above copyright notice,
'       this list of conditions and the following disclaimer.
'     * Redistributions in binary form must reproduce the above copyright
'       notice, this list of conditions and the following disclaimer in the
'       documentation and/or other materials provided with the distribution.
'     * Neither the name of the software nor the names of its contributors may
'       be used to endorse or promote products derived from this software
'       without specific prior written permission.
' 
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
' IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
' ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
' LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
' CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
' SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
' INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
' CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
' ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
' POSSIBILITY OF SUCH DAMAGE.
' 
' 
' 
SuperStrict

Module wb.colorvalue

ModuleInfo "Version: 1.0"
ModuleInfo "Copyright: 2005 William Bailey <wb@...;"
ModuleInfo "Author: William Bailey"
ModuleInfo "License: BSD"

ModuleInfo "History: 17/11/2005 1.0 Release"

Type ColorValue
	
	Global floatValue:Float[] = [0.000000000,0.00392156886,0.00784313772,0.0117647061,0.0156862754,0.0196078438,0.0235294122,0.0274509806,0.0313725509,0.0352941193,0.0392156877,0.0431372561,0.0470588244,0.0509803928,0.0549019612,0.0588235296,0.0627451017,0.0666666701,0.0705882385,0.0745098069,0.0784313753,0.0823529437,0.0862745121,0.0901960805,0.0941176489,0.0980392173,0.101960786,0.105882354,0.109803922,0.113725491,0.117647059,0.121568628,0.125490203,0.129411772,0.133333340,0.137254909,0.141176477,0.145098045,0.149019614,0.152941182,0.156862751,0.160784319,0.164705887,0.168627456,0.172549024,0.176470593,0.180392161,0.184313729,0.188235298,0.192156866,0.196078435,0.200000003,0.203921571,0.207843140,0.211764708,0.215686277,0.219607845,0.223529413,0.227450982,0.231372550,0.235294119,0.239215687,0.243137255,0.247058824,0.250980407,0.254901975,0.258823544,0.262745112,0.266666681,0.270588249,0.274509817,0.278431386,0.282352954,0.286274523,0.290196091,0.294117659,0.298039228,0.301960796,0.305882365,0.309803933,0.313725501,0.317647070,0.321568638,0.325490206,0.329411775,0.333333343,0.337254912,0.341176480,0.345098048,0.349019617,0.352941185,0.356862754,0.360784322,0.364705890,0.368627459,0.372549027,0.376470596,0.380392164,0.384313732,0.388235301,0.392156869,0.396078438,0.400000006,0.403921574,0.407843143,0.411764711,0.415686280,0.419607848,0.423529416,0.427450985,0.431372553,0.435294122,0.439215690,0.443137258,0.447058827,0.450980395,0.454901963,0.458823532,0.462745100,0.466666669,0.470588237,0.474509805,0.478431374,0.482352942,0.486274511,0.490196079,0.494117647,0.498039216,0.501960814,0.505882382,0.509803951,0.513725519,0.517647088,0.521568656,0.525490224,0.529411793,0.533333361,0.537254930,0.541176498,0.545098066,0.549019635,0.552941203,0.556862772,0.560784340,0.564705908,0.568627477,0.572549045,0.576470613,0.580392182,0.584313750,0.588235319,0.592156887,0.596078455,0.600000024,0.603921592,0.607843161,0.611764729,0.615686297,0.619607866,0.623529434,0.627451003,0.631372571,0.635294139,0.639215708,0.643137276,0.647058845,0.650980413,0.654901981,0.658823550,0.662745118,0.666666687,0.670588255,0.674509823,0.678431392,0.682352960,0.686274529,0.690196097,0.694117665,0.698039234,0.701960802,0.705882370,0.709803939,0.713725507,0.717647076,0.721568644,0.725490212,0.729411781,0.733333349,0.737254918,0.741176486,0.745098054,0.749019623,0.752941191,0.756862760,0.760784328,0.764705896,0.768627465,0.772549033,0.776470602,0.780392170,0.784313738,0.788235307,0.792156875,0.796078444,0.800000012,0.803921580,0.807843149,0.811764717,0.815686285,0.819607854,0.823529422,0.827450991,0.831372559,0.835294127,0.839215696,0.843137264,0.847058833,0.850980401,0.854901969,0.858823538,0.862745106,0.866666675,0.870588243,0.874509811,0.878431380,0.882352948,0.886274517,0.890196085,0.894117653,0.898039222,0.901960790,0.905882359,0.909803927,0.913725495,0.917647064,0.921568632,0.925490201,0.929411769,0.933333337,0.937254906,0.941176474,0.945098042,0.949019611,0.952941179,0.956862748,0.960784316,0.964705884,0.968627453,0.972549021,0.976470590,0.980392158,0.984313726,0.988235295,0.992156863,0.996078432,1.00000000]
	
	Field value:Int
	
	Method New ()
		value = 0
	End Method
	
	Method get:Int ()
		Return value
	End Method
	
	Method getR:Byte ()
		Return (value & $FF000000) Shr 24
	End Method

	Method getG:Byte ()
		Return (value & $00FF0000) Shr 16
	End Method
	
	Method getB:Byte ()
		Return (value & $0000FF00) Shr 8
	End Method
	
	Method getA:Byte ()
		Return (value & $000000FF)
	End Method
	
	Method getRFloat:Float ()
		Return self.floatValue[getR()]
	End Method

	Method getGFloat:Float ()
		Return self.floatValue[getG()]
	End Method
	
	Method getBFloat:Float ()
		Return self.floatValue[getB()]
	End Method

	Method getAFloat:Float ()
		Return self.floatValue[getA()]
	End Method
	
	Method set (v:Int)
		value = v
	End Method
	
	Method setRGBA (r:Byte, g:Byte, b:Byte, a:Byte)
		value = (r Shl 24) | (g Shl 16) | (b Shl 8) | a
	End Method
	
	Method setR (v:Byte)
		value = (value & $00FFFFFF) | (v Shl 24)
	End Method
	
	Method setG (v:Byte)
		value = (value & $FF00FFFF) | (v Shl 16)
	End Method
	
	Method setB (v:Byte)
		value = (value & $FFFF00FF) | (v Shl 8)
	End Method
	
	Method setA (v:Byte)
		value = (value & $FFFFFF00) | v
	End Method
	
	Method setRGBAFloat (r:Float, g:Float, b:Float, a:Float)
		setRFloat(r)
		setGFloat(g)
		setBFloat(b)
		setAFloat(a)
	End Method
	
	Method setRFloat (v:Float)
		If v > 1.0 Then
			v = 1.0
		Else If v < 0.0 Then
			v = 0.0
		End If
		setR(Int(255 * v))
	End Method

	Method setGFloat (v:Float)
		If v > 1.0 Then
			v = 1.0
		Else If v < 0.0 Then
			v = 0.0
		End If
		setG(Int(255 * v))
	End Method

	Method setBFloat (v:Float)
		If v > 1.0 Then
			v = 1.0
		Else If v < 0.0 Then
			v = 0.0
		End If
		setB(Int(255 * v))
	End Method

	Method setAFloat (v:Float)
		If v > 1.0 Then
			v = 1.0
		Else If v < 0.0 Then
			v = 0.0
		End If
		setA(Int(255 * v))
	End Method

	Method gammaCorrection (v:Float)
		Local vr:Int = getR() ^ v
		Local vg:Int = getG() ^ v
		Local vb:Int = getB() ^ v
		If vr > 255 Then
			vr = 255
		Else If vr < 0 Then
			vr = 0
		End If
		If vg > 255 Then
			vg = 255
		Else If vg < 0 Then
			vg = 0
		End If
		If vb > 255 Then
			vb = 255
		Else If vb < 0 Then
			vb = 0
		End If
		setRGBA(vr, vg, vb, getA())
	End Method
	
	Method interpolate:ColorValue (c:ColorValue, amount:Float)
		Local newC:ColorValue = New ColorValue
		newC.setR(getR() + amount * (c.getR() - getR()))
		newC.setG(getG() + amount * (c.getG() - getG()))
		newC.setB(getB() + amount * (c.getB() - getB()))
		newC.setA(getA() + amount * (c.getA() - getA()))
		Return newC
	End Method

End Type


coordinate.bmx
' 
' 
' Copyright (c) 2005, William Bailey <wb@...;
' All rights reserved.
' 
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are met:
' 
'     * Redistributions of source code must retain the above copyright notice,
'       this list of conditions and the following disclaimer.
'     * Redistributions in binary form must reproduce the above copyright
'       notice, this list of conditions and the following disclaimer in the
'       documentation and/or other materials provided with the distribution.
'     * Neither the name of the software nor the names of its contributors may
'       be used to endorse or promote products derived from this software
'       without specific prior written permission.
' 
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
' IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
' ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
' LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
' CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
' SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
' INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
' CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
' ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
' POSSIBILITY OF SUCH DAMAGE.
' 
' 
' 
SuperStrict

Module wb.coordinate

ModuleInfo "Version: 1.0"
ModuleInfo "Copyright: 2005 William Bailey <wb@...;"
ModuleInfo "Author: William Bailey"
ModuleInfo "License: BSD"

ModuleInfo "History: 17/11/2005 1.0 Release"

Type Coordinate
	
	Field x:Float
	Field y:Float
	Field z:Float

	Method set(c:Coordinate)
		x = c.getX()
		y = c.getY()
		z = c.getZ()
	End Method

	Method setXYZ(xv:Float, yv:Float, zv:Float)
		x = xv
		y = yv
		z = zv
	End Method

	Method setX (value:Float)
		x = value
	End Method

	Method setY (value:Float)
		y = value
	End Method

	Method setZ (value:Float)
		z = value
	End Method

	Method getX:Float()
		Return x
	End Method

	Method getY:Float()
		Return y
	End Method

	Method getZ:Float()
		Return z
	End Method
	
	Method applyDelta(c:Coordinate)
		x = x + c.getX()
		y = y + c.getY()
		z = z + c.getZ()
	End Method

End Type



A simple 'rain' ParticleSystem...
particlesystemrain.bmx
' 
' 
' Copyright (c) 2005, William Bailey <wb@...;
' All rights reserved.
' 
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are met:
' 
'     * Redistributions of source code must retain the above copyright notice,
'       this list of conditions and the following disclaimer.
'     * Redistributions in binary form must reproduce the above copyright
'       notice, this list of conditions and the following disclaimer in the
'       documentation and/or other materials provided with the distribution.
'     * Neither the name of the software nor the names of its contributors may
'       be used to endorse or promote products derived from this software
'       without specific prior written permission.
' 
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
' IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
' ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
' LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
' CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
' SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
' INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
' CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
' ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
' POSSIBILITY OF SUCH DAMAGE.
' 
' 
' 
SuperStrict

Module wb.particleSystemRain

ModuleInfo "Version: 1.0"
ModuleInfo "Copyright: 2005 William Bailey <wb@...;"
ModuleInfo "Author: William Bailey"
ModuleInfo "License: BSD"

ModuleInfo "History: 17/11/2005 1.0 Release"

Import brl.max2d
Import brl.random
Import brl.math

Import wb.particle

Type RainParticleSystem Extends ParticleSystem
	
	Global vx:Int
	Global vy:Int
	Global vw:Int
	Global vh:Int
	
	Field texture:TImage
	Field wind:Float
	
	Method New()
		texture   = Null
		particles = Null
		wind      = 0
	End Method
	
	Method setTexture (t:TImage)
		texture = t
		MidHandleImage(texture)
	End Method
	
	Method setWind (value:Float)
		wind = value
		If particles Then
			For Local p:Particle = EachIn particles
				p.velocity.setX(wind)
				If wind = 0.0 Then
					p.rotation = 0
				Else
					p.rotation = -ATan(p.velocity.getX() / p.velocity.getY())
				End If		
			Next 
		End If		
	End Method
	
	Method setParticles (total:Int)
		GetViewport(vx, vy, vw, vh)
		particles = New Particle[total]
		For Local i:Int = 0 To particles.length - 1
			particles[i] = New Particle
			setParticleDefaults(particles[i])
			particles[i].position.setY(particles[i].position.getY() - Rand(0, vh))
		Next		
	End Method

	Method update:Int ()
		GetViewport(vx, vy, vw, vh)
		Local pWidth:Int = 0
		Local pHeight:Int = 0
		If texture Then
			pWidth = texture.width
			pHeight = texture.height
		End If
		If particles Then
			For Local p:Particle = EachIn particles
				p.update()
				If wind > 0.0 And p.position.getX() > vx + vw + Int(pWidth * p.size) Then
					p.position.setX(vx - Int(pWidth * p.size))
				Else If wind < 0.0 And p.position.getX() < vx - Int(pWidth * p.size) Then
					p.position.setX(vx + vw + Int(pWidth * p.size))
				End If
				If p.position.getY() > vy + vh + Int(pHeight * p.size) Then
					setParticleDefaults(p)
				End If
			Next
		End If
		Return True
	End Method
	
	Method setParticleDefaults ( p:Particle )
		Local pWidth:Int = 0
		Local pHeight:Int = 0
		If texture Then
			pWidth = texture.width
			pHeight = texture.height
		End If
		p.energy = 1
		p.size = Rnd(0.2, 1)
		p.position.setXYZ(Rand(vx - Int(pWidth * p.size), vx + vw + Int(pWidth * p.size)), vy - Int(pHeight * p.size), 0)
		p.oldPosition.set(p.position)
		p.color.setA(Rand(80, 200))
		p.rotationDelta = 0
		p.velocity.setXYZ(wind, Rnd(1.0, 3.0), 0)
		If wind = 0.0 Then
			p.rotation = 0
		Else
			p.rotation = -ATan(p.velocity.getX() / p.velocity.getY())
		End If		
	End Method
	
	Method preRender ()
		SetBlend(ALPHABLEND)
		SetColor(255, 255, 255)
	End Method
	
	Method renderParticle ( p:Particle )
		If Not texture Then
			Return
		End If
		SetAlpha(colorValue.floatValue[p.color.getA()])
		SetRotation(p.rotation)
		SetScale(p.size, p.size)
		DrawImage(texture, p.position.getX(), p.position.getY())
	End Method
	
	Method postRender ()
	End Method

End Type


Example usage...
SuperStrict

Framework BRL.Basic

Import BRL.GLMax2D
Import BRL.PNGLoader

Import wb.particle
Import wb.particleSystemRain

SeedRnd(MilliSecs())

SetGraphicsDriver(GLMax2DDriver())
Graphics(640,480, 0, 75)

Local pm:ParticleManager = New ParticleManager

Local rain:RainParticleSystem = New RainParticleSystem
rain.setTexture(LoadImage("rain.png", FILTEREDIMAGE | MIPMAPPEDIMAGE))
rain.setWind(0.7)
rain.setParticles(256)
pm.addSystem(rain)

While Not KeyHit(KEY_ESCAPE)
	Cls
		
	pm.update()
	pm.render()	
	
	SetBlend(ALPHABLEND)
	SetScale(1, 1)
	SetAlpha(1)
	SetRotation(0)
	SetColor(255, 255, 255)
	DrawText "      Mem: " + (GCMemAlloced() / 1024) + "K", 10, 25
	DrawText "  Systems: " + pm.system.count(), 10, 40
	DrawText "Particles: " + pm.particleCount(), 10, 55
	Flip
End While
EndGraphics()



Hope this helps a little.


Eric(Posted 2005) [#7]
Wow...thanks for the information... I will print this out and pick through it. I appreciate your help.


Eric(Posted 2005) [#8]
What do you think is the best...make a pool of particles or create them on the fly?


Lomat(Posted 2005) [#9]
I create a pool of particles and then reuse them after they 'die' hense the setParticleDefaults() method. This saves you haveing to create and destroy a few hundred particles every update and should remove the need for garbage collection of the dead particles and mem allocation for the new particles.

YMMV so give both a try and see what works best for you. :)


BlackSp1der(Posted 2006) [#10]
The rain looks more like snow. is a little slow.

your module doesn't have a "setGRAVITY"?


Lomat(Posted 2006) [#11]
I posted a few simple examples to show how everything works togeather. The rain and snow particle systems that i posted will most likely not suit everybody but they worked well for that application that they were intended for :)

The point is that you can extend and build upon the base types (more specifically extending ParticleSystem) to create the functionality specific to your application(s). As long as you implement the required ParticleSystem interface you can simply add and remove particle systems at will and share them between applications without any fuss.


Anyway going back to the rain being a little slow...

The Y velocity of the rain is being set in the setParticleDefaults() method in the RainParticleSystem type using the following line:

p.velocity.setXYZ(wind, Rnd(1.0, 3.0), 0)

Just amend the above line to suit your needs. Or create your own RealWorldRainParticleSystem with all the methods that you require :)