Hi guys,
I’ve written a fireworks demo based on a nice JS tutorial (http://creativejs.com/tutorials/creating-fireworks/). I’m struggling a bit to improve the performance a bit. Any suggestions?
-- Main
displayMode(FULLSCREEN)
-- Use this function to perform your initial setup
function setup()
fpsmin = 55555555
fireworks = Fireworks()
fireworks:addFirework()
fireworks:addFirework()
fireworks:addFirework()
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(0, 0, 0, 255)
fill(231, 223, 231, 255)
local fps = math.floor(1/DeltaTime)
text("fps = "..fps, 100,100)
fpsmin = math.min(fps, fpsmin)
text("min fps = "..fpsmin, 100,150)
fireworks:draw()
end
function touched(touch)
if touch.state == ENDED then
fireworks:addFirework()
end
end
Particle = class()
-- Represents a single point, so the firework being fired up
-- into the air, or a point in the exploded firework
function Particle:init(pos, target, vel, marker, usePhysics)
-- properties for animation
-- and colouring
self.alive = true
self.GRAVITY = -0.06
self.alpha = 1
self.easing = math.random() * 0.02
self.fade = math.random() * 0.15
self.colors = {
vec3(9, 251, 237, 255),
vec3(153, 255, 0, 255),
vec3(208, 0, 255, 255),
vec3(235, 14, 230, 255),
vec3(0, 22, 255, 255),
vec3(22, 246, 4, 255),
vec3(9, 0, 255, 255),
vec3(250, 255, 0, 255),
vec3(255, 19, 0)
}
self.color_ = marker
self.pos = vec2(
pos.x or 0,
pos.y or 0
)
self.vel = vec2(
vel.x or 0,
vel.y or 0
)
self.lastPos = vec2(
self.pos.x,
self.pos.y
)
self.target = vec2(0,
target.y or 0
)
self.usePhysics = usePhysics or false
end
function Particle:draw()
local x = math.ceil(self.pos.x)
local y = math.ceil(self.pos.y)
local xVel = (x - self.lastPos.x) * -3
local yVel = (y - self.lastPos.y) * -3
local firecolor = self.colors[self.color_]
--tail
smooth()
strokeWidth(1)
stroke(firecolor.x, firecolor.y, firecolor.z, 2550*self.alpha)
line(self.pos.x-2.5, self.pos.y-2.5, self.pos.x + xVel, self.pos.y + yVel)
-- glow
smooth()
tint(255, 255, 255, 150*self.alpha)
sprite(fireworks.CIRCLEIMG, x - 3, y - 3, 15)
-- colored spark
noSmooth()
tint(firecolor.x, firecolor.y, firecolor.z, 2550*self.alpha)
sprite(fireworks.CIRCLEIMG, x - 3, y - 3)
end
function Particle:update()
self.lastPos.x = self.pos.x
self.lastPos.y = self.pos.y
if self.usePhysics then
self.vel.y = self.vel.y + self.GRAVITY
self.pos.y = self.pos.y + self.vel.y
-- since this value will drop below
-- zero we'll occasionally see flicker,
-- ... just like in real life! Woo! xD
if self.alpha - self.fade >= 0 then
self.alpha = self.alpha - self.fade
else
self.alpha = 0
end
else
local distance = (self.target.y - self.pos.y)
-- ease the position
self.pos.y = self.pos.y + distance * (0.03 + self.easing)
-- cap to 1
self.alpha = math.min(distance * distance * 0.00005, 1)
end
self.pos.x = self.pos.x + self.vel.x
return self.alpha < 0.005
end
FireworksExplosion = class()
function FireworksExplosion:init()
self.particles = {}
self.ended = false
end
function FireworksExplosion:draw()
local k = 1
local particleDrawn = false
-- for i=1,table.getn(self.particles) do
for i,firework in pairs(self.particles) do
--local firework = self.particles[i]
if firework and firework:update() then
self.particles[i] = nil
-- if not using physics, then explode
if not firework.usePhysics then
self:circle(firework)
end
else
self.particles[k] = self.particles[i]
if k ~= i then
self.particles[i] = nil
end
k = k + 1
end
if firework then
particleDrawn = true
firework:draw()
end
end
if not particleDrawn then
self.ended = true
end
end
function FireworksExplosion:circle(firework)
local count = 80
local angle = (math.pi * 2) / count
while count > 0 do
local randomVelocity = 4 + math.random() * 4
local particleAngle = count * angle
self:createParticle(
firework.pos,
null,
vec2 (
math.cos(particleAngle) * randomVelocity,
math.sin(particleAngle) * randomVelocity
),
firework.color_,
true)
count = count - 1
end
end
function FireworksExplosion:createParticle(pos, target, vel, color_, usePhysics)
pos = pos or {}
target = target or {}
vel = vel or {}
table.insert(self.particles,
Particle(
-- position
vec2(
pos.x or WIDTH * 0.5,
pos.y or 10
),
-- target
vec2(
0,
target.y or 2*HEIGHT/3 + math.random() * 100
),
-- velocity
vec2(
vel.x or math.random() * 3 - 1.5,
vel.y or 0
),
color_ or math.floor(math.random() * 100) % 9 + 1,
usePhysics)
)
end
function FireworksExplosion:createFirework()
self:createParticle()
end
Fireworks = class()
function Fireworks:init()
self.explosions = {}
fpsmin = 55555555
self.CIRCLEIMG = self:circleImage(5)
end
function Fireworks:draw()
for i, v in ipairs(self.explosions) do
if not v.ended then
v:draw()
end
end
end
function Fireworks:addFirework()
local ex = FireworksExplosion()
ex:createFirework()
table.insert(self.explosions, ex)
end
function Fireworks:circleImage( size )
local i = image(size,size)
setContext(i)
pushStyle()
noStroke()
fill(255) -- fill white, we can tint() the image
ellipse( size/2, size/2, size )
popStyle()
setContext()
return i
end