Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Cartoon Explosions from Two Lives Left Development Blog
return (function()
-- CartoonExplosions
-- @Description: Tap for make an explosion ! Double tap for a random color explosion. (Tap while an explosion is in progress will pause the effect)
-- @Author: Two Lives Left (port for Codea by Hyro Vitaly Protago)
-- @Link: http://twolivesleft.com/prototypes/cartoon-explosions/
CAN_PAUSE = true
PAUSED = false
function setup()
-- configs
ellipseMode(CENTER)
smooth()
noStroke()
explosions = ExplosionMaker()
test = 0
end
function draw()
background(0)
pushMatrix()
translate(WIDTH*.5, HEIGHT*.5)
if not PAUSED then
test = test + 1
if test % 2 == 0 then -- #Hyro : added for view at 30 fps
explosions:update(1/30)
test = 0
end
end
explosions:draw()
popMatrix()
if PAUSED then
fill(255)
text("PAUSED", WIDTH*.5, HEIGHT*.5)
end
end
function touched(touch)
if touch.state ~= ENDED then
return
end
if PAUSED then
PAUSED = false
return
end
if CAN_PAUSE and explosions.started then
PAUSED = true
end
if touch.tapCount == 2 then
explosions.explosionColor = color(math.random(0,255), math.random(0,255), math.random(0,255), 255)
else
explosions.explosionColor = color(255, 55, 0)
end
explosions.innerColor = color(0,0,0,255)
explosions:explode()
end
--------------------------------------------------------
-- Circle
--------------------------------------------------------
Circle = class()
function Circle:init(x, y, ss)
self.position = vec2(x or 0, y or 0)
self.direction = vec2(0, -1)
self.circleSize = ss or nil
end
--------------------------------------------------------
-- CircularExpand
--------------------------------------------------------
CircularExpand = class()
CircularExpand.EASE_IN = 0
CircularExpand.EASE_OUT = 1
CircularExpand.LONG_EASE_OUT = 2
CircularExpand.VERY_LONG_EASE_OUT = 3
function CircularExpand:init(numParticles)
self.seed = math.floor(math.random(0, 10000000000))
self.easeMode = CircularExpand.LONG_EASE_OUT
self.started = false
self.circleColor = color(255, 100, 0)
self.position = vec2(0,0)
self.time = 0
self.startingSize = 20
self.endingSize = 200
self.speedFactor = 10
self.duration = .5
self.startingRadius = 10
self.endingRadius = 500
self.particles = {}
for i = 1,numParticles do
self.particles[#self.particles+1] = Circle()
end
end
function CircularExpand:explode()
math.randomseed(self.seed)
self.started = true
for i = 1, #self.particles do
self.particles[i] = Circle(math.random(-self.startingRadius, self.startingRadius), math.random(-self.startingRadius, self.startingRadius), self.startingSize)
self.particles[i].endingSize = math.random(self.endingSize * .5, self.endingSize)
self.particles[i].speed = math.random(self.speedFactor * .5, self.speedFactor)
self.particles[i].direction = vec2(self.particles[i].position.x, self.particles[i].position.y)
self.particles[i].direction = self.particles[i].direction:normalize()
end
end
local function easeIn(x) -- 3/2x^2 - 1/2x^3
return x*x*(1.5-.5*x)
end
local function easeOut(x)
local inv_x = 1-x
return 1 - inv_x * inv_x * ( 1.5 - .5 * inv_x )
end
local function longEaseOut(x)
local inv_x = 1-x
return 1 - inv_x * inv_x * inv_x * inv_x * ( 1.5 - .5 * inv_x )
end
local function veryLongEaseOut(x)
local inv_x = 1-x
return 1 - math.pow(inv_x,8) * ( 1.5 - .5 * inv_x )
end
function CircularExpand:update(delta)
if not self.started then
return
end
self.time = self.time + delta
local elapsed = 0
if self.easeMode == CircularExpand.EASE_IN then
elapsed = easeIn(self.time / self.duration)
elseif self.easeMode == CircularExpand.EASE_OUT then
elapsed = easeOut(self.time / self.duration)
elseif self.easeMode == CircularExpand.LONG_EASE_OUT then
elapsed = longEaseOut(self.time / self.duration)
elseif self.easeMode == CircularExpand.VERY_LONG_EASE_OUT then
elapsed = veryLongEaseOut(self.time / self.duration)
end
for i = 1, #self.particles do -- Update each particle
self.particles[i].position = self.particles[i].position + (self.particles[i].direction * self.particles[i].speed)
self.particles[i].circleSize = (self.particles[i].endingSize - self.startingSize) * elapsed + self.startingSize
end
if elapsed >= 1 then
self.started = false
end
end
function CircularExpand:draw()
if not self.started then
return
end
pushMatrix()
translate(self.position.x, self.position.y)
pushStyle()
fill(self.circleColor)
for i = 1, #self.particles do
ellipse(self.particles[i].position.x, self.particles[i].position.y, self.particles[i].circleSize, self.particles[i].circleSize)
end
popMatrix()
popStyle()
end
--------------------------------------------------------
-- ExplosionMaker
--------------------------------------------------------
ExplosionMaker = class()
function ExplosionMaker:init()
self.started = false
self.durationFact = 1
self.innerDelay = .4 * self.durationFact
self.detailInnerDelay = .08 * self.durationFact
self.explosionColor = color(255, 100, 0)
self.innerColor = color(255)
end
function ExplosionMaker:explode()
if self.started then
return
end
self.time = 0
self.started = true
self.inner = CircularExpand(30)
self.outer = CircularExpand(20)
self.detailBits = CircularExpand(15)
self.detailMask = CircularExpand(20)
-- Configure
self.outer.circleColor = self.explosionColor
self.detailBits.circleColor = self.explosionColor
self.detailMask.circleColor = self.innerColor
self.inner.circleColor = color(self.innerColor.r, self.innerColor.g, self.innerColor.b, 200)
self.outer.easeMode = CircularExpand.VERY_LONG_EASE_OUT
self.inner.easeMode = CircularExpand.VERY_LONG_EASE_OUT
self.detailBits.easeMode = CircularExpand.VERY_LONG_EASE_OUT
self.detailMask.easeMode = CircularExpand.VERY_LONG_EASE_OUT
self.outer.seed = self.inner.seed
self.detailBits.seed = self.inner.seed
self.detailMask.seed = self.inner.seed
self.detailBits.startingSize = 4
self.detailMask.startingSize = 10
self.inner.startingSize = 10
self.detailBits.endingSize = 35
self.detailMask.endingSize = 60
self.outer.endingSize = 120
self.inner.endingSize = 140
self.detailBits.speedFactor = 12
self.detailMask.speedFactor = 15
self.outer.speedFactor = 5
self.inner.speedFactor = 9
self.outer.duration = .8 * self.durationFact
self.inner.duration = .7 * self.durationFact
self.detailBits.duration = .4 * self.durationFact
self.detailMask.duration = .31 * self.durationFact -- #Hyro (.31) hide ellipse at the end
-- Start exploding outer
self.outer:explode()
end
function ExplosionMaker:finish()
self.started = false
self.inner = nil
self.outer = nil
self.detailBits = nil
end
function ExplosionMaker:update(delta)
if not self.started then
return
end
self.time = self.time + delta
if not self.inner.started and self.time >= self.innerDelay then
self.inner:explode()
self.detailBits:explode()
end
if not self.detailMask.started and self.time >= (self.innerDelay + self.detailInnerDelay) then
self.detailMask:explode()
end
self.outer:update(delta)
self.inner:update(delta)
self.detailBits:update(delta)
self.detailMask:update(delta)
if not self.inner.started and not self.outer.started then
self:finish()
end
end
function ExplosionMaker:draw()
if not self.started then
return
end
self.outer:draw()
self.inner:draw()
self.detailBits:draw()
self.detailMask:draw()
end
end)
{
"name":"CartoonExplosions",
"description":"Cartoon Explosions from Two Lives Left Development Blog",
"author":"HyroVitalyProtago",
"version":"0.0.0"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment