Code archives/3D Graphics - Effects/Simple particles

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

Download source code

Simple particles by H. T. U.2008
A list of particle functions (examples here: http://blitzbasic.com/Community/posts.php?topic=82290 ). Uses mostly Blitz commands for manipulating particles and emitters. Great for beginners and simple effects.

Limitations: For Blitz commands to be compatible with this system, each particle is a separate entity (and consequently surface) and requires For/Next statements to select each particle and emitter. Therefore it is best for simple effects only.

Well, enjoy!
Global totalparticles;Total number of particles ever created



Type emitter
	
	Field pt
	Field mx#,my#,mz#
	Field rmx#,rmy#,rmz#
	Field pitch#,yaw#,roll#
	Field rpitch#,ryaw#,rroll#
	Field fade
	
End Type

Type particle
	
	Field sprite
	Field emitter
	Field mx#,my#,mz#
	Field pitch#,yaw#,roll#
	Field alpha#
	Field fade
	Field life
	Field ctime
	Field id
	
End Type





Function createemitter(mx#,my#,mz#,pitch#,yaw#,roll#,rm#=0,rr#=0,fade=True);Create an emitter

	
	e.emitter=New emitter
	e\pt=CreatePivot();emitter entity
	;particle motion and rotation(including random amounts)
	e\mx=mx
	e\my=my
	e\mz=mz
	e\rmx=rm
	e\rmy=rm
	e\rmz=rm
	e\pitch=pitch
	e\yaw=yaw
	e\roll=roll
	e\rpitch=rr
	e\ryaw=rr
	e\rroll=rr
	e\fade=fade;particle fading


	
	Return e\pt
	
End Function

Function createparticle(emitter,life#);Create a particle
	;get the emitter
	For e.emitter=Each emitter
		If e\pt=emitter
			a=Handle(e.emitter)
		EndIf
	Next
	emtr.emitter=Object.emitter(a)
	
	If emtr.emitter=Null RuntimeError "Emitter doesn't exist";stop the program if the emitter doesn't exist
			
			totalparticles=totalparticles+1;update the particle count
			
			TFormVector emtr\mx,emtr\my,emtr\mz,emtr\pt,0;keep the particle on track no matter what the emitter's rotation
						
			p.particle=New particle
			p\sprite=CreateSprite()
			p\emitter=emitter
			;particle movement and rotation values	
			p\mx=TFormedX()+Rnd(-(emtr\rmx),emtr\rmx)
			p\my=TFormedY()+Rnd(-(emtr\rmy),emtr\rmy)
			p\mz=TFormedZ()+Rnd(-(emtr\rmz),emtr\rmz)
			p\pitch=emtr\pitch+Rnd(-(emtr\rpitch),emtr\rpitch)
			p\yaw=emtr\yaw+Rnd(-(emtr\ryaw),emtr\ryaw)
			p\roll=emtr\roll+Rnd(-(emtr\rroll),emtr\rroll)
			p\alpha=1
			;particle fading and life values
			p\fade=emtr\fade
			p\life=life
			p\ctime=MilliSecs()
			p\id=totalparticles;used for getparticle

			PositionEntity p\sprite,EntityX(emtr\pt),EntityY(emtr\pt),EntityZ(emtr\pt)
		
			Return p\sprite

End Function

Function particlealpha(particle,alpha#);changes the particles base alpha (required for proper fading)

	For p.particle=Each particle
		If p\sprite=particle p\alpha=alpha;set the particle's base alpha to alpha
	Next
	
End Function

Function updateparticles();update every particle's movement, rotation, and fading

	For p.particle=Each particle
		If p.particle<>Null
		
			TranslateEntity p\sprite,p\mx,p\my,p\mz
			TurnEntity p\sprite,p\pitch,p\yaw,p\roll
		
			If p\fade=True;if the particle is supposed to fade out of existence
			
				alpha#=p\alpha-(p\alpha*(MilliSecs()-p\ctime)/p\life)

			EndIf
			EntityAlpha p\sprite,alpha
			
			If alpha<=0;if the particle's alpha is zero or less
				freeparticle(p\sprite)
			EndIf
					
		EndIf
	Next
	
End Function

Function countparticles(emitter);returns the number of particles produced by an emitter currently in existence
	
	For p.particle=Each particle
		If p\emitter=emitter;if emitter is the particle's emitter
			cnt=cnt+1
		EndIf			
	Next
	
	Return cnt
				
End Function

Function getparticle(id);

	For p.particle=Each particle
		If p.particle<>Null And p\id=id;if the particle exists and it's id equals id			
			Return p\sprite
		EndIf
	Next			

End Function

Function partmovex#(particle);returns a particle's x movement
		
	For p.particle=Each particle
		If p.particle<>Null And p\sprite=particle;if the particle exists and it's sprite is the supplied particle
			Return p\mx
		EndIf
	Next
	
End Function

Function partmovey#(particle);returns a particle's y movement
		
	For p.particle=Each particle
		If p.particle<>Null And p\sprite=particle;if the particle exists and it's sprite is the supplied particle
			Return p\my
		EndIf
	Next
	
End Function

Function partmovez#(particle);returns a particle's z movement
		
	For p.particle=Each particle
		If p.particle<>Null And p\sprite=particle;if the particle exists and it's sprite is the supplied particle
			Return p\mz
		EndIf
	Next
	
End Function

Function partpitch#(particle);returns a particle's pitch rotation
		
	For p.particle=Each particle
		If p.particle<>Null And p\sprite=particle;if the particle exists and it's sprite is the supplied particle
			Return p\pitch
		EndIf
	Next
	
End Function

Function partyaw#(particle);returns a particle's yaw rotation
		
	For p.particle=Each particle
		If p.particle<>Null And p\sprite=particle;if the particle exists and it's sprite is the supplied particle
			Return p\yaw
		EndIf
	Next
	
End Function

Function partroll#(particle);returns a particle's roll rotation
		
	For p.particle=Each particle
		If p.particle<>Null And p\sprite=particle;if the particle exists and it's sprite is the supplied particle
			Return p\roll
		EndIf
	Next
	
End Function

Function modifyparticle(particle,mx#,my#,mz#,pitch#=0,yaw#=0,roll#=0,life=1000,fade=True,rel=False);changes a particle after it's created

	For p.particle=Each particle
		If p.particle<>Null And p\sprite=particle;if the particle exists and it's sprite is the supplied particle
			If rel=False;if the change isn't relative
				p\mx=mx
				p\my=my
				p\mz=mz
				p\pitch=pitch
				p\yaw=yaw
				p\roll=roll
				p\life=life
				p\fade=fade
			Else;if it is
				p\mx=p\mx+mx
				p\my=p\my+my
				p\mz=p\mz+mz
				p\pitch=p\pitch+pitch
				p\yaw=p\yaw+yaw
				p\roll=p\roll+roll
				p\life=p\life+life
				If fade=False p\fade=Not p\fade
			EndIf
		EndIf
	Next
	
End Function

Function freeparticle(particle);removes a particle

	For p.particle=Each particle
		If p\sprite=particle
			FreeEntity p\sprite
			Delete p
		EndIf
	Next

End Function

Function modifyemitter(emitter,mx#,my#,mz#,pitch#=0,yaw#=0,roll#=0,rm#=0,rr#=0,fade=True,rel=False);changes an emitter after it's created
	;get the emitter
	For e.emitter=Each emitter		
		If e\pt=emitter
			a=Handle(e.emitter)
		EndIf
	Next
	emtr.emitter=Object.emitter(a)

	If emtr.emitter=Null RuntimeError "Emitter doesn't exist";stop the program if the emitter doesn't exist

	If rel=False;if the change isn't relative
		emtr\mx=mx
		emtr\my=my
		emtr\mz=mz
		emtr\rmx=rm
		emtr\rmy=rm
		emtr\rmz=rm
		emtr\pitch=pitch
		emtr\yaw=yaw
		emtr\roll=roll
		emtr\rpitch=rr
		emtr\ryaw=rr
		emtr\rroll=rr
		emtr\fade=fade
	Else;if it is
		emtr\mx=emtr\mx+mx
		emtr\my=emtr\my+my
		emtr\mz=emtr\mz+mz
		emtr\rmx=emtr\rmx+rm
		emtr\rmy=emtr\rmy+rm
		emtr\rmz=emtr\rmz+rm
		emtr\pitch=emtr\pitch+pitch
		emtr\yaw=emtr\yaw+yaw
		emtr\roll=emtr\roll+roll
		emtr\rpitch=emtr\rpitch+rr
		emtr\ryaw=emtr\ryaw+rr
		emtr\rroll=emtr\rroll+rr
		If fade=True emtr\fade=Not emtr\fade
	EndIf	
End Function

Function modifyemitterrnd(emitter,rmx#,rmy#,rmz#,rpitch#,ryaw#,rroll#);change an emitter's random values in depth
	;get the emitter
	For e.emitter=Each emitter		
		If e\pt=emitter
			a=Handle(e.emitter)
		EndIf
	Next
	emtr.emitter=Object.emitter(a)
	
	emtr\rmx=rmx
	emtr\rmy=rmy
	emtr\rmz=rmz
	emtr\rpitch=rpitch
	emtr\ryaw=ryaw
	emtr\rroll=rroll
	
End Function

Function freeemitter(emitter);removes an emitter
	
	For e.emitter=Each emitter
		If e\pt=emitter
			FreeEntity e\pt
			Delete e
		EndIf
	Next
	
End Function

Function clearparticlesystem();removes the entire particle system

	For e.emitter=Each emitter
		If e<>Null
			If e\pt=True FreeEntity e\pt
			Delete e
		EndIf
	Next
	
	For p.particle=Each particle
		If p<>Null
			If p\sprite=True FreeEntity p\sprite
			Delete p
		EndIf
	Next

End Function

Comments

BlitzSupport2008
Hello HTU,

I suspect that the reason you're having problems is simply because (I assume) you don't realise you can return any type from a function, including user-defined types such as your 'entity' and 'particle' types.

For instance:

Function createemitter (mx#,my#,mz#,pitch#,yaw#,roll#,rm#=0,rr#=0,fade=True);Create an emitter
	
	e.emitter=New emitter
	e\pt=CreatePivot();emitter entity

; etc

	Return e\pt
	
End Function


Here, you're creating e.emitter in your function, then returning its pivot field, instead of just returning e.emitter. You should modify this to return the e.emitter you've created, then pass 'e.emitter' to your other functions -- note that the function name has the type appended below, ie .emitter:

Function createemitter.emitter (mx#,my#,mz#,pitch#,yaw#,roll#,rm#=0,rr#=0,fade=True);Create an emitter
	
	e.emitter=New emitter
	e\pt=CreatePivot();emitter entity

; etc

	Return e ; Not e\pt
	
End Function


Note that the call would have to be made as myemitter.emitter = createemitter (x,y,z), ie. using the .emitter type to receive the result.

Then, for any functions that use the returned value from createemitter...

Old:

Function freeemitter(emitter);removes an emitter
	
	For e.emitter=Each emitter
		If e\pt=emitter
			FreeEntity e\pt
			Delete e
		EndIf
	Next
	
End Function


New:

Function freeemitter(e.emitter);removes an emitter

	If e
		Delete e
	EndIf

End Function


Note that the parameter's type is defined as an emitter, ie. you should pass the .emitter type you received from createemitter ().

As you'll see, this removes all the For/Next checks too. You probably won't need the Object/Handle calls either if you do this.

The same goes for your particle type and its associated functions.


H. T. U.2009
Thanks, but I returned the entity on purpose so that it would be easy for beginners, without having to deal with particle types in their main code. This makes it somewhat slow, but it's more of a intro to particles.


Chroma2009
Heck you dont' want to teach them bad habits now do you? :)

I agree on returning the type.


Jeppe Nielsen2009
Your could return the the entity (pivot) and set the name to the type handle:


Function createemitter (mx#,my#,mz#,pitch#,yaw#,roll#,rm#=0,rr#=0,fade=True);Create an emitter
	
	e.emitter=New emitter
	e\pt=CreatePivot();emitter entity
        NameEntity e\pt,Handle(e); <-- notice this

; etc

	Return e\pt
	
End Function


And to delete:


Function freeemitter(emitter);removes an emitter
	
        e.emitter = Object.emitter(EntityName(emitter))

	FreeEntity emitter
	Delete e
	
End Function



thus removing the foreach loop also.

This is what I do in my particle systems in blitz3d


Code Archives Forum