Particle Timing

BlitzMax Forums/BlitzMax Programming/Particle Timing

Schragnasher(Posted 2008) [#1]
I am in need of some help, iv been working this problem for a few weeks now and cant get it right. Iv searched the forum but haven't found much luck on the specifics of timing a particle system to different machine speeds. I want to have a consistent rate of emission on any pc, i know it might slow down the game(like how eschalon gets slow) of a really slow PC but that's ok, I would add a slider for effects. I just want to make sure it looks decent on a fast machine, right now it seems to emit a bunch of particles then stop and emit a few seconds later when the die. I'm using a timing function that i found in the code DB. I just don't know where i need to multiply the AppSpeed() in my particle update. Frankly im not sure if im even doing any of the timing stuff right for it at all. I understand the regular animation timing, and it works, its just an issue with how im doing it in the particle system. Ill post the code, but i cant promise itl make much sense lol. Any help on this is appreciated if im making sense.

Timing Function below
Module mymods.timing

Private

Global AppTime_UPS
Global AppTime_Iterator
Global AppTime_CurrentTime
Global AppTime_PauseStart=0
Global AppTime_Speed:Float=1.0
Global AppTime_DesiredLoopTime#=1000.0/60.0
Global AppTime_LastUpdateTime=0
Global AppTime_LastUPSTime

Public

Rem
bbdoc:
EndRem
Function UpdateAppTime(framerate=60)
	Local time
	Local elapsed
	
	If AppTime_PauseStart Return
	
	AppTime_DesiredLoopTime=1000.0/framerate

	time=MilliSecs()

	If AppTime_LastUpdateTime=0
		AppTime_Speed#=1.0
		AppTime_LastUpdateTime=time
		AppTime_CurrentTime=time
		AppTime_LastUPSTime=time
	Else
		elapsed=time-AppTime_LastUpdateTime
		If Not elapsed
			elapsed=1
			Delay 1
			time:+1
		EndIf
		AppTime_Speed=Float(elapsed)/Float(AppTime_DesiredLoopTime)
		AppTime_CurrentTime=time
		AppTime_LastUpdateTime=time
	EndIf
	
	AppTime_Iterator:+1
	If AppTime_CurrentTime-AppTime_LastUPSTime>=1000
		AppTime_UPS=Float(AppTime_Iterator)/(Float(AppTime_CurrentTime-AppTime_LastUPSTime)/1000.0)
		AppTime_LastUPSTime=AppTime_CurrentTime
		AppTime_Iterator=0
	EndIf
	
EndFunction

Rem
bbdoc:
EndRem
Function AppTime()
	Return AppTime_CurrentTime
EndFunction

Rem
bbdoc:
EndRem
Function AppSpeed#()
	Return AppTime_Speed
EndFunction

Rem
bbdoc:
EndRem
Function UPS:Int()
	Return AppTime_UPS
EndFunction

Rem
bbdoc:
EndRem
Function PauseApp()
	If AppTime_PauseStart Return
	AppTime_PauseStart=MilliSecs()
EndFunction

Rem
bbdoc:
EndRem
Function ResumeApp()
	If Not AppTime_PauseStart Return
	If AppTime_LastUpdateTime
		Local elapsed=MilliSecs()-AppTime_PauseStart
		AppTime_LastUpdateTime:+elapsed
	EndIf
	AppTime_PauseStart=0
EndFunction


My particle code if it helps.
Type tJParticle
	Field x:Float
	Field y:Float
	Field r:Byte
	Field g:Byte
	Field b:Byte
	Field alpha:Float
	Field scale:Float
	Field rot:Float
	Field xspeed:Float
	Field yspeed:Float
	Field age:Float = 0
	Function Create:tJParticle(x:Float, y:Float, initialalpha:Float, initialscale:Float, initialxspeed:Float, initialyspeed:Float)
		Local temp:tJParticle = New tJParticle
		temp.x = x
		temp.y = y
		temp.alpha = initialalpha
		temp.scale = initialscale
		temp.xspeed = initialxspeed
		temp.yspeed = initialyspeed
		Return temp
	End Function
End Type
Type tJEmitter
	Field partimg:tImg = LoadImg("particle.png")
	Field Layer1:TList = CreateList()
	Field pmax:Int
	Field x:Float
	Field y:Float
	Field frame:Float
	Field emitdelay:Float = 1
	Field emitrate:Int = 1
	
	Field blendmode:Int = LIGHTBLEND
	Field pred:Int = 200
	Field pgreen:Int = 100
	Field pblue:Int = 50
	Field xaccel:Float = 0
	Field yaccel:Float =.0001
	Field initialalpha:Float = 1
	Field initialalphajitter:Float = 0
	Field alphadecay:Float =.01
	Field alphadecayjitter:Float = 0
	
	Field initialscale:Float = 0
	Field initialscalejitter:Float = 0
	Field scalerate:Float =.01
	Field scaleratejitter:Float = 0
	
	Field lifetime:Float = 200
	Method Update()
		Local time:Int = MilliSecs()
		For Local t:tJParticle = EachIn layer1
				t.x = t.x + (t.xspeed * AppSpeed())
				t.y = t.y + (t.yspeed * AppSpeed())
				t.alpha = t.alpha - (alphadecay * AppSpeed())
				t.scale = t.scale + (scalerate * AppSpeed())
				If t.alpha <= 0 Or t.age >= lifetime Then
					ListRemove(layer1, t)
				End If
				t.age:+1 * AppSpeed()
		Next
		If layer1.Count() < pmax And frame >= emitdelay Then
			For Local e:Int = 0 To emitrate
				ListAddLast(layer1, tJParticle.Create(x, y, initialalpha, initialscale, Rnd(- 1, 1), - 1))
			Next
			frame = 0
		Else
			frame:+AppSpeed()
		End If
		
	End Method
	Method Draw()
		RenderState.Push()
		SetBlend(blendmode)
		For Local t:tJParticle = EachIn layer1
			SetColor(pred, pgreen, pblue)
			SetAlpha(t.alpha)
			SetScale(t.scale, t.scale)
			DrawImg(partimg, t.x, t.y)
		Next
		RenderState.Pop()
		DrawText(layer1.Count(), x, y - 30)
	End Method
	Function Create:tJEmitter(x:Float, y:Float, pmax:Int)
		Local temp:tJEmitter = New tJEmitter
		temp.pmax = pmax
		temp.x = x
		temp.y = y
		Return temp
	End Function
End Type
Type tJParticleSystem Extends tGameObject
	Field emitters:TList = CreateList()
	Method Draw()
		For Local t:tJEmitter = EachIn emitters
			t.Draw()
		Next
	End Method
	Method Update()
		For Local t:tJEmitter = EachIn emitters
			t.x = x
			t.y = y
			t.Update()
		Next
	End Method
	Method CreateEmitter(pmax:Int)
		ListAddLast(emitters, tJEmitter.Create(x, y, pmax))
	End Method
	Function Create:tJParticleSystem(name:String, x:Float, y:Float)
		Local temp:tJParticleSystem = New tJParticleSystem
		temp.name = name
		temp.x = x
		temp.y = y
		ListAddLast(tGameObject.objectlist, temp)
		Return temp
	End Function
End Type

Function GetParticleSystem:tJParticleSystem(name:String)
	For Local t:tJParticleSystem = EachIn tGameObject.objectlist
		If t.name = name Then Return t
	Next
	Throw "psystem not found: " + name
End Function

Function CreateJParticleSystem:tJParticleSystem(name:String, x:Float, y:Float)
	Return tJParticleSystem.Create(name, x, y)
End Function

Function AddEmitter(system:Object, pmax:Int)
	If tJParticleSystem(system) Then
		tJParticleSystem(system).CreateEmitter(pmax)
	Else If String(system) Then
		GetParticleSystem(String(system)).CreateEmitter(pmax)
	End If
End Function






Muttley(Posted 2008) [#2]
Have a read of this: http://www.gaffer.org/game-physics/fix-your-timestep


Schragnasher(Posted 2008) [#3]
thanks i think that might be what im looking for!


Muttley(Posted 2008) [#4]
No problem. :)

I think there's a couple of BlitzMax examples of that method floating around these forums if you get stuck.