Skip to content

Instantly share code, notes, and snippets.

@itsbth
Created November 7, 2011 00:58
Show Gist options
  • Select an option

  • Save itsbth/1343935 to your computer and use it in GitHub Desktop.

Select an option

Save itsbth/1343935 to your computer and use it in GitHub Desktop.
Uploaded by UploadToGist for Sublime Text 2
local Vector
do
local V_MT, sqrt, type, unpack, setmetatable = {}, math.sqrt, type, unpack, setmetatable
V_MT.__index = V_MT
function V_MT:__add(b)
return Vector(self.x + b.x, self.y + b.y)
end
function V_MT:__sub(b)
return Vector(self.x - b.x, self.y - b.y)
end
function V_MT:__mul(b)
return Vector(self.x * b, self.y * b)
end
function V_MT:__div(b)
return Vector(self.x / b, self.y / b)
end
function V_MT:__tostring()
return ("{%f, %f}"):format(self.x, self.y)
end
function V_MT:length()
return math.sqrt(self.x * self.x + self.y * self.y)
end
function V_MT:length2()
return self.x * self.x + self.y * self.y
end
function V_MT:normalized()
return self / self:length()
end
function Vector(x, y)
if type(x) == 'table' then
if x.x then
x, y = x.x, x.y
else
x, y = unpack(x)
end
end
return setmetatable({x = x or 0, y = y or 0}, V_MT)
end
end
local Particle, ParticleSystem
do
local PT_PROTO = {}
PT_PROTO.__index = PT_PROTO
function PT_PROTO:init(data)
data = data or {}
self.birth = love.timer.getMicroTime()
self.lifetime = data.lifetime
self.vel = data.vel or Vector(0, 0)
if self.setup then self:setup(data) end
end
function PT_PROTO:think(dt)
self.pos = self.pos + self.vel * dt
self.age = love.timer.getMicroTime() - self.birth
if self.lifetime < self.age then
if not (self.death and self:death()) then
self.dead = true
end
end
if self.update then self:update(dt) end
end
function Particle(tbl)
tbl.__index = tbl
setmetatable(tbl, PT_PROTO)
return function (system, pos, ...)
local part = {system, pos = pos}
setmetatable(part, tbl)
if part.init then part:init(...) end
return part
end
end
local PS_MT = {}
PS_MT.__index = PS_MT
function PS_MT:create(pos, ...)
self.particles[#self.particles + 1] = self:pt_create(pos, ...)
end
function PS_MT:draw()
for _, v in ipairs(self.particles) do
if v and not v.dead then v:draw() end
end
end
function PS_MT:think(dt)
for _, v in ipairs(self.particles) do
if v and not v.dead then v:think(dt) end
end
end
function PS_MT:trim()
-- XXX: skips one particle per particle removed
for i = 1, #self.particles do
-- TODO: Break out of loop if self.particles[i] == nil?
if self.particles[i] and self.particles[i].dead then
table.remove(self.particles, i)
end
end
end
function ParticleSystem(new_part)
local ps = {pt_create = new_part, particles = {}}
setmetatable(ps, PS_MT)
return ps
end
end
Explosion = Particle {
setup = function (self, data)
self.elapsed = 0
self.color = data.color
end,
draw = function (self)
local r, t = (1 - (love.timer.getMicroTime() - self.birth) / self.lifetime), self.pos - self.vel:normalized() * 0.5
if r < 0.1 then r = 1 end
self.color[4] = 255 * r
love.graphics.setColor(self.color)
love.graphics.line(self.pos.x, self.pos.y, t.x, t.y)
end,
update = function (self, dt)
if self.age > 0.1 and not self.slowdown then
self.vel = self.vel / 200
self.slowdown = true
end
end
}
Rocket = Particle {
setup = function (self, data)
self.emitter = data.emitter
self.sound = data.sound
self.trail = {self.pos.x, self.pos.y}
end,
update = function (self, dt)
self.vel.y = self.vel.y + 100*dt*dt
self.trail[#self.trail + 1] = self.pos.x
self.trail[#self.trail + 1] = self.pos.y
end,
draw = function (self)
--local endp = self.pos - self.vel / 2
love.graphics.setColor(255, 255, 255)
love.graphics.line(self.trail)
end,
death = function (self)
local color = {math.random() * 255, math.random() * 255, math.random() * 255}
for i = 1, 1000 do
local ang, vel = math.random() * 2 * math.pi, math.random() * 500
vel = Vector(math.sin(ang), math.cos(ang)) * vel
self.emitter:create(self.pos, {
vel = vel,
lifetime = 5 + math.random() * 3,
color = color
})
end
love.audio.play(self.sound)
end
}
local explosions, rockets, boom, nr
function love.load()
explosions = ParticleSystem(Explosion)
rockets = ParticleSystem(Rocket)
boom = love.sound.newSoundData("explosion.ogg")
nr = 0
end
function love.update(dt)
if nr < love.timer.getMicroTime() then
local mpos, spos, ttl = Vector(50 + math.random() * (love.graphics.getWidth() - 100), 50 + math.random() * 100), Vector(math.random() * love.graphics.getWidth(), love.graphics.getHeight()), 3 + math.random() * 2
rockets:create(spos, {
emitter = explosions,
vel = (mpos - spos) / ttl,
lifetime = ttl,
sound = love.audio.newSource(boom)
})
nr = love.timer.getMicroTime() + math.random() * 3
end
explosions:think(dt)
explosions:trim()
rockets:think(dt)
rockets:trim()
end
function love.draw()
rockets:draw()
explosions:draw()
end
function love.mousepressed(x, y, button)
local mpos, spos, ttl = Vector(x, y), Vector(math.random() * love.graphics.getWidth(), love.graphics.getHeight()), 3 + math.random() * 2
rockets:create(spos, {
emitter = explosions,
vel = (mpos - spos) / ttl,
lifetime = ttl,
sound = love.audio.newSource(boom)
})
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment