Skip to content

Instantly share code, notes, and snippets.

@Stavr0gin
Created August 2, 2012 16:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Stavr0gin/3238197 to your computer and use it in GitHub Desktop.
Save Stavr0gin/3238197 to your computer and use it in GitHub Desktop.
Particular particle system
-- Copyright 2012 Javier Moral
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
t = 0.0
lastGen = 0.0
fps = 0
frameCount = 0
smokeButtonPos = vec2(60,30)
flameButtonPos = vec2(170,30)
dustButtonPos = vec2(60,90)
trailButtonPos = vec2(170,90)
anim = false
animAngle = 0
-- Use this function to perform your initial setup
function setup()
backingMode(RETAINED)
iparameter("Draw_Emitters",0,1,0)
iparameter("Particles_Sec",0,200,100)
iparameter("Emitter_SizeX",0,500,0)
iparameter("Emitter_SizeY",0,500,0)
iparameter("Life",0,100,30)
iparameter("Life_Variation",0,100,0)
iparameter("PartSize",0,100,35)
iparameter("PartSize_Variation",0,100,0)
iparameter("Part_End_Life_Size",-1,500,-1)
parameter("Velocity",0,50,10)
iparameter("Velocity_Variation",0,100,0)
parameter("Rotation_Speed",-0.2,0.2,0)
iparameter("Rotation_Speed_Variation",0,100,0)
iparameter("Opacity",0,255,255)
iparameter("Opacity_Variation",0,100,0)
iparameter("Opacity_End",-1,255,-1)
iparameter("WindX",-50,50,0)
parameter("Air_Resistance",0,1,0.1)
parameter("Gravity_Val",-5,5,0)
iparameter("Use_Gravity_Vector",0,1,0)
iparameter("Size_Wiggle",0,1,0)
iparameter("Turbulence_Pos_Affect",0,20,0)
emitter = Particular(WIDTH/2,HEIGHT/2)
presetDefault()
end
-- This function gets called once every frame
function draw()
loadParameters()
noSmooth()
fill(0, 0, 0, 255)
rect(0,0,WIDTH,HEIGHT)
if anim == true then
animateEmitter()
end
emitter:draw()
if (Draw_Emitters == 1) then
fill(0, 230, 255, 255)
strokeWidth(3)
stroke(255, 255, 255, 255)
ellipse(emitter.x,emitter.y,20)
noStroke()
end
if frameCount == 31 then
frameCount = 0
else
frameCount = frameCount + 1
end
t = t + DeltaTime
if frameCount == 30 then
fps = 1.0/DeltaTime
end
fontSize(15)
font("ArialMT")
fill(255)
text(string.format("Fps: %2.2f",fps),WIDTH - 60, 30)
text(string.format("Time: %2.2f",t), WIDTH - 60, 50)
drawButtons()
end
function drawButtons()
fill(94, 0, 255, 81)
rect(5,5,220,130)
fill(255)
text("Presets:",40,125)
font("Baskerville-Bold")
fill(242, 41, 41, 255)
fontSize(30)
drawButton(smokeButtonPos.x,
smokeButtonPos.y,
"Smoke")
drawButton(flameButtonPos.x,
flameButtonPos.y,
"Flame")
drawButton(dustButtonPos.x,
dustButtonPos.y,
"Dust")
drawButton(trailButtonPos.x,
trailButtonPos.y,
"Trail")
end
function animateEmitter()
emitter.x = WIDTH/2 + math.cos(animAngle) * 150
emitter.y = HEIGHT/2 + math.sin(animAngle) * 150
animAngle = animAngle + 0.05
end
function loadParameters()
emitter.partPerSec = Particles_Sec
emitter.sizeX = Emitter_SizeX
emitter.sizeY = Emitter_SizeY
emitter.life = Life
emitter.lifeVariation = Life_Variation
emitter.initPartSize = PartSize
emitter.partSizeVariation = PartSize_Variation
emitter.finalPartSize = Part_End_Life_Size
emitter.velocity = Velocity
emitter.velocityVariation = Velocity_Variation
emitter.rotSpd = Rotation_Speed
emitter.rotSpdVariation = Rotation_Speed_Variation
emitter.initOpacity = Opacity
emitter.opacityVariation = Opacity_Variation
emitter.finalOpacity = Opacity_End
emitter.windX = WindX
emitter.airResistance = Air_Resistance
emitter.gravity = Gravity_Val
emitter.useGravityVector = Use_Gravity_Vector
emitter.sizeWiggle = Size_Wiggle
emitter.turbulencePosAffect = Turbulence_Pos_Affect
end
function drawButton(x,y,caption)
font("ArialRoundedMTBold")
sprite("Cargo Bot:Dialogue Button",x,y)
fill(84, 84, 84, 255)
fontSize(30)
text(caption,x+1,y+1)
fill(255)
fontSize(30)
text(caption,x,y)
end
function touched(touch)
if(touch.state == ENDED) then
if isTouched(touch.x,
touch.y,
smokeButtonPos.x - 20,
smokeButtonPos.y - 20,
smokeButtonPos.x + 20,
smokeButtonPos.y + 20) then
presetSmoke()
sound(SOUND_HIT,1)
return
end
if isTouched(touch.x,
touch.y,
flameButtonPos.x - 20,
flameButtonPos.y - 20,
flameButtonPos.x + 20,
flameButtonPos.y + 20) then
presetFlame()
sound(SOUND_HIT,1)
return
end
if isTouched(touch.x,
touch.y,
dustButtonPos.x - 20,
dustButtonPos.y - 20,
dustButtonPos.x + 20,
dustButtonPos.y + 20) then
presetDust()
sound(SOUND_HIT,1)
return
end
if isTouched(touch.x,
touch.y,
trailButtonPos.x - 20,
trailButtonPos.y - 20,
trailButtonPos.x + 20,
trailButtonPos.y + 20) then
presetTrail()
sound(SOUND_HIT,1)
return
end
end
if anim == false and isTouched(touch.x,
touch.y,
emitter.x - 40,
emitter.y - 40,
emitter.x + 40,
emitter.y + 40) then
emitter.x = touch.x
emitter.y = touch.y
if emitter.y < 150 then
emitter.y = 150
end
return
end
end
function isTouched(tx,ty,x1,y1,x2,y2)
if tx >= x1 and tx <= x2 then
if ty >= y1 and ty <= y2 then
return true
end
end
return false
end
function presetDefault()
anim = false
emitter.particularMesh.texture = "Cargo Bot:Star"
Particles_Sec = 100
Life = 30
Life_Variation = 0
PartSize = 35
PartSize_Variation = 0
Part_End_Life_Size = -1
Velocity = 10
Velocity_Variation = 0
Rotation_Speed = 0
Rotation_Speed_Variation = 0
Opacity = 255
Opacity_Variation = 0
Opacity_End = -1
Air_Resistance = 0.1
Gravity_Val = 0
Use_Gravity_Vector = 0
Size_Wiggle = 0
Turbulence_Pos_Affect = 0
end
function presetSmoke()
anim = false
emitter.particularMesh.texture = "Cargo Bot:Smoke Particle"
Emitter_SizeX = 0
Emitter_SizeY = 0
Particles_Sec = 10
Life = 60
Life_Variation = 20
PartSize = 10
PartSize_Variation = 100
Part_End_Life_Size = 155
Velocity = 5.7
Velocity_Variation = 100
Rotation_Speed = 0.08
Rotation_Speed_Variation = 45
Opacity = 125
Opacity_Variation = 100
Opacity_End = 20
WindX = 0
Air_Resistance = 0.2
Gravity_Val = -1.15
Use_Gravity_Vector = 0
Size_Wiggle = 0
Turbulence_Pos_Affect = 0
end
function presetFlame()
anim = false
emitter.particularMesh.texture =
"Tyrian Remastered:Explosion Huge"
Emitter_SizeX = 0
Emitter_SizeY = 0
Particles_Sec = 100
Life = 30
Life_Variation = 50
PartSize = 55
PartSize_Variation = 100
Part_End_Life_Size = 0
Velocity = 2
Velocity_Variation = 100
Rotation_Speed = 0.2
Rotation_Speed_Variation = 0
Opacity = 100
Opacity_Variation = 100
Opacity_End = 255
WindX = 0
Air_Resistance = 0.1
Gravity_Val = -1
Use_Gravity_Vector = 0
Size_Wiggle = 0
Turbulence_Pos_Affect = 5
end
function presetDust()
anim = false
emitter.particularMesh.texture =
"Tyrian Remastered:Energy Orb 1"
Emitter_SizeX = WIDTH - 100
Emitter_SizeY = HEIGHT - 100
Particles_Sec = 100
Life = 150
Life_Variation = 50
PartSize = 5
PartSize_Variation = 95
Part_End_Life_Size = 0
Velocity = 0
Velocity_Variation = 0
Rotation_Speed = 0.2
Rotation_Speed_Variation = 50
Opacity = 70
Opacity_Variation = 80
Opacity_End = 0
WindX = -10
Air_Resistance = 0.1
Gravity_Val = 0.3
Use_Gravity_Vector = 0
Size_Wiggle = 0
Turbulence_Pos_Affect = 5
end
function presetTrail()
anim = true
emitter.particularMesh.texture =
"Cargo Bot:Star Filled"
Emitter_SizeX = 5
Emitter_SizeY = 5
Particles_Sec = 100
Life = 150
Life_Variation = 50
PartSize = 15
PartSize_Variation = 90
Part_End_Life_Size = 5
Velocity = 1.9
Velocity_Variation = 90
Rotation_Speed = 0.2
Rotation_Speed_Variation = 50
Opacity = 180
Opacity_Variation = 80
Opacity_End = 5
WindX = -5
Air_Resistance = 0.1
Gravity_Val = -0.05
Use_Gravity_Vector = 0
Size_Wiggle = 1
Turbulence_Pos_Affect = 5
end
-- Copyright 2012 Javier Moral
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
Particular = class()
function Particular:init(x,y)
self.x = x
self.y = y
self.sizeX = 0
self.sizeY = 0
self.partPerSec = 2
self.life = 30
self.lifeVariation = 0
self.rotSpd = 0.0
self.rotSpdVariation = 0
self.initPartSize = 35
self.partSizeVariation = 0
self.finalPartSize = -1
self.velocity = 10
self.velocityVariation = 0
self.initOpacity = 255
self.opacityVariation = 0
self.finalOpacity = -1
self.windX = 0
self.airResistance = 0.1
self.gravity = 0
self.useGravityVector = 0
self.sizeWiggle = 0
self.turbulencePosAffect = 0
self.rects = {}
self.deadRects = {}
self.parts = {}
self.particularMesh = mesh()
self.evo = 0
self.tSinceLast = 0.0
self.particleLimit = 50
end
function Particular:draw()
self.tSinceLast = self.tSinceLast + DeltaTime
local tCreation = 1 / self.partPerSec
local partCreated = 0
if self.partPerSec == 0 then
self.tSinceLast = 0
end
-- Creating new particles
while (self.tSinceLast > tCreation) do
partCreated = partCreated + 1
if (partCreated<=self.particleLimit)then
self.tSinceLast = self.tSinceLast-tCreation
else
self.tSinceLast = 0
end
self:createParticle()
end
local resistance = 1/(self.airResistance + 1)
-- Calculating gravity
local g
if self.useGravityVector > 0 then
if self.gravity == 0 then
g = vec2(0,0)
else if self.gravity > 0 then
g = vec2(Gravity.x,Gravity.y)
else
g = vec2(-Gravity.x,-Gravity.y)
end
end
else
g = vec2(0,-self.gravity)
end
for k,i in ipairs(self.rects) do
local p = self.parts[i]
-- Calculating turbulence
local nx = 0
local ny = 0
if self.turbulencePosAffect>0 then
local n = noise(p.x,p.y,self.evo)
if n > 0 then
n = n - math.floor(n)
else
n = n - math.ceil(n)
end
nx = n * math.cos(self.evo)
ny = n * math.sin(self.evo)
self.evo = self.evo + 1
if self.evo > 9999 then
self.evo = 0
end
end
if (p.lifeLeft > 0) then
-- Calculating position and velocity
p.x = p.x + p.v.x +
self.windX * 0.1 +
self.turbulencePosAffect*nx
p.y = p.y + p.v.y +
self.turbulencePosAffect*ny
p.v = p.v + g
p.v = p.v * resistance
local lifePercentage = (p.life-p.lifeLeft)/p.life
-- Calculating size
local size
if self.finalPartSize >= 0 then
local sizeInc = self.finalPartSize - p.initSize
size = (lifePercentage*sizeInc)+p.initSize
else
size = p.initSize
end
if ((self.sizeWiggle>0)and(size>1)) then
size = math.random(size)
end
if (size<0) then
size = 0
end
-- Calculating opacity
local opacity
if self.finalOpacity >= 0 then
local opacityInc = self.finalOpacity - p.initOpacity
opacity = (lifePercentage*opacityInc)+p.initOpacity
else
opacity = p.initOpacity
end
-- Calculating rotation
p.angle = p.angle + p.rotSpd
p.lifeLeft = p.lifeLeft - 1
self.particularMesh:setRect(i,p.x,p.y,size,size,p.angle)
self.particularMesh:setRectColor(i,255,255,255,opacity)
else
local deadPart = self.parts[i]
if not deadPart.isDead then
table.insert(self.deadRects,i)
self.particularMesh:setRect(i,0,0,0,0)
deadPart.isDead = true
end
end
end
self.particularMesh:draw()
end
function Particular:createParticle()
local psize = genNumber(self.initPartSize,self.partSizeVariation)
local v = vec2(math.random(-100,100),math.random(-100,100))
v = v:normalize()
v = v * genNumber(self.velocity,self.velocityVariation)
local partX = self.x + math.random(-self.sizeX,self.sizeX)
local partY = self.y + math.random(-self.sizeY,self.sizeY)
local particle = Particle(partX,
partY,
psize,
genNumber(self.life,self.lifeVariation),
v,
0,
genNumber(self.initOpacity,self.opacityVariation),
genNumber(self.rotSpd,self.rotSpdVariation))
local index
if (self.deadRects[1]==nil) then
index = self.particularMesh:addRect(self.x,
self.y,
psize,
psize)
table.insert(self.rects, index)
table.insert(self.parts, particle)
else
index = self.deadRects[1]
table.remove(self.deadRects,1)
self.particularMesh:setRect(index,
self.x,
self.y,
psize,
psize)
self.parts[index] = particle
end
self.particularMesh:setRectColor(index,255,255,255,
particle.initOpacity)
end
function genNumber(number,variation)
if variation == 0.0 then
return number
end
if number == 0 then
return number
end
number = number * 1000
mult = true
ret = variation*0.01*math.abs(number)
ret = number + math.random(-ret,ret)
ret = ret / 1000
return ret
end
--
-- Particle class
--
Particle = class()
Particle.DEFAULT_OPACITY = 125
Particle.DEFAULT_ANGLE = 0
Particle.DEFAULT_MASS = 1
function Particle:init(posx,posy,size,life,
velocity,angle,opacity,rotSpd)
-- position
self.x = posx
self.y = posy
-- size
self.initSize = size
-- velocity
self.v = velocity
-- life
self.life = life
self.lifeLeft= life
-- angle
if angle == nil then
self.angle = self.DEFAULT_ANGLE
else
self.angle = angle
end
-- rotation speed
if rotSpd==nil then
self.rotSpd = 0.0
else
self.rotSpd = rotSpd
end
-- opacity
self.initOpacity = opacity
self.isDead = false
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment