Last active
August 29, 2015 15:56
-
-
Save HyroVitalyProtago/6b85d82eb534a4c8a844 to your computer and use it in GitHub Desktop.
Cartoon Explosions from Two Lives Left Development Blog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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