threading, sound generation, effects
This commit is contained in:
parent
3f60135f02
commit
b40e21afe7
14 changed files with 1995 additions and 77 deletions
|
@ -10,7 +10,8 @@ multilily = lily.loadMulti({
|
|||
{lily.newImage, "assets/ships/decorator.png"},
|
||||
{lily.newImage, "assets/ships/particle.png"},
|
||||
{lily.newImage, "assets/particle.png"},
|
||||
{lily.newImage, "assets/tiles/gf.png"}
|
||||
{lily.newImage, "assets/tiles/gf.png"},
|
||||
{lily.newImage, "assets/explosion.png"}
|
||||
})
|
||||
multilily:onComplete(function(_, lilies)
|
||||
gameLogo = lilies[1][1]
|
||||
|
@ -24,8 +25,8 @@ multilily:onComplete(function(_, lilies)
|
|||
CaptainJohn.ship.image = lilies[9][1]
|
||||
boosterParticle = lilies[10][1]
|
||||
titleParticle = lilies[11][1]
|
||||
|
||||
tileGroundFull = lilies[12][1]
|
||||
explosionParticle = lilies[13][1]
|
||||
|
||||
windowWidth = love.graphics.getWidth()
|
||||
windowHeight = love.graphics.getHeight()
|
||||
|
|
BIN
assets/explosion.png
Normal file
BIN
assets/explosion.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
BIN
assets/sounds/explosion.ogg
Normal file
BIN
assets/sounds/explosion.ogg
Normal file
Binary file not shown.
|
@ -8,9 +8,8 @@ function Player:new()
|
|||
self.px = 0
|
||||
self.py = 0
|
||||
self.rot = 0
|
||||
self.speed = 5
|
||||
self.acc = 0
|
||||
self.accIncr = 0.1
|
||||
self.death = false
|
||||
end
|
||||
|
||||
function Player:getShipname()
|
||||
|
|
5
conf.lua
5
conf.lua
|
@ -1,14 +1,13 @@
|
|||
function love.conf(t)
|
||||
t.title = "Vision"
|
||||
t.author = "The Impossible Astronaut"
|
||||
t.version = "11.4" -- The LÖVE version this game was made for (string)
|
||||
t.version = "11.4"
|
||||
t.identity = "Vision"
|
||||
t.gammacorrect = false
|
||||
t.gammacorrect = true
|
||||
|
||||
t.width = 800
|
||||
t.height = 600
|
||||
|
||||
t.window.borderless = false
|
||||
t.window.msaa = 4
|
||||
t.window.highdpi = true
|
||||
end
|
8
main.lua
8
main.lua
|
@ -18,9 +18,14 @@ function love.load()
|
|||
Object = require "vendor/classic"
|
||||
|
||||
require "vendor/math"
|
||||
flux = require "vendor/flux"
|
||||
sfxr = require "vendor.sfxr"
|
||||
|
||||
moonshine = require "shaders"
|
||||
effect = moonshine(moonshine.effects.vignette).chain(moonshine.effects.filmgrain)
|
||||
effect = moonshine(moonshine.effects.chromasep).chain(moonshine.effects.godsray).chain(moonshine.effects.vignette).chain(moonshine.effects.filmgrain)
|
||||
effect.chromasep.angle=1
|
||||
effect.chromasep.radius=1
|
||||
effect.godsray.weight=0
|
||||
effect.vignette.softness = 0.4
|
||||
effect.vignette.opacity = 0.2
|
||||
effect.filmgrain.size = 2
|
||||
|
@ -56,6 +61,7 @@ function love.load()
|
|||
end
|
||||
|
||||
function love.update(dt)
|
||||
flux.update(dt)
|
||||
if currentScene ~= nil then
|
||||
currentScene:update(dt)
|
||||
end
|
||||
|
|
38
planet/mapthread.lua
Normal file
38
planet/mapthread.lua
Normal file
|
@ -0,0 +1,38 @@
|
|||
channel = {}
|
||||
channel.tomap = love.thread.getChannel("tomap")
|
||||
channel.blocks = love.thread.getChannel("blocks")
|
||||
|
||||
function generateMapBlock(mapWidth, mapHeight)
|
||||
local block = {}
|
||||
local center = math.ceil( mapWidth/2 )
|
||||
local defaultWidth=8
|
||||
|
||||
-- Fill empty
|
||||
for y=1, mapHeight do
|
||||
local row = {}
|
||||
for x=1, mapWidth do
|
||||
table.insert(row, 0)
|
||||
end
|
||||
|
||||
table.insert(block, row)
|
||||
end
|
||||
|
||||
-- Draw simple road
|
||||
for y=1, mapHeight do
|
||||
for x=center-(defaultWidth/2), center+(defaultWidth/2) do
|
||||
block[y][x] = 1
|
||||
end
|
||||
end
|
||||
|
||||
return block
|
||||
end
|
||||
|
||||
while true do
|
||||
local tomap = channel.tomap:pop()
|
||||
if tomap then
|
||||
if tomap.message == "generateblock" then
|
||||
channel.blocks:push(generateMapBlock( tomap.width, tomap.height ))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -8,49 +8,49 @@ function Planet:init()
|
|||
self.canvas = love.graphics.newCanvas(windowWidth, windowHeight)
|
||||
|
||||
self.map = {
|
||||
{0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
|
||||
}
|
||||
|
||||
self.spritemap = {
|
||||
s1= tileGroundFull
|
||||
}
|
||||
|
||||
self.hasGeneratedMap = false
|
||||
|
||||
self.mapThread = love.thread.newThread("planet/mapthread.lua")
|
||||
self.mapThread:start()
|
||||
self.channel = {}
|
||||
self.channel.tomap = love.thread.getChannel("tomap")
|
||||
self.channel.blocks = love.thread.getChannel("blocks")
|
||||
|
||||
self:generateMapBlock()
|
||||
end
|
||||
|
||||
function Planet:update(dt)
|
||||
local error = self.mapThread:getError()
|
||||
assert( not error, error )
|
||||
|
||||
local blocks = self.channel.blocks:pop()
|
||||
if blocks then
|
||||
for y = 1, table.getn(blocks) do
|
||||
table.insert(self.map, blocks[y])
|
||||
end
|
||||
|
||||
self:draw()
|
||||
self.hasGeneratedMap = true
|
||||
end
|
||||
end
|
||||
|
||||
function Planet:draw()
|
||||
local maplen = table.getn(self.map)
|
||||
if maplen > 0 then
|
||||
love.graphics.setCanvas(self.canvas)
|
||||
--self.canvas:clear()
|
||||
|
||||
love.graphics.setColor(1,1,1,1)
|
||||
|
||||
local sprite = nil
|
||||
local pos = 0
|
||||
for y=1, 20 do
|
||||
for y=1, math.min(maplen,20) do
|
||||
for x=1, 25 do
|
||||
sprite = nil
|
||||
pos = self.map[y][x]
|
||||
|
@ -63,3 +63,8 @@ function Planet:draw()
|
|||
|
||||
love.graphics.setCanvas()
|
||||
end
|
||||
end
|
||||
|
||||
function Planet:generateMapBlock()
|
||||
self.channel.tomap:push( { message= "generateblock", width= 25, height= 60 } )
|
||||
end
|
138
scene/game.lua
138
scene/game.lua
|
@ -7,6 +7,8 @@ function GameScene:init()
|
|||
GameScene:playerChanged(currentPlayer)
|
||||
movementDelta = 0
|
||||
|
||||
love.audio.setPosition( windowWidth/2, windowHeight/2,0)
|
||||
|
||||
pSystem = love.graphics.newParticleSystem(boosterParticle,128)
|
||||
pSystem:setParticleLifetime(0,0.6)
|
||||
pSystem:setLinearAcceleration(0,20,0,25)
|
||||
|
@ -28,28 +30,62 @@ function GameScene:init()
|
|||
1,1,1,0.3
|
||||
)
|
||||
|
||||
eSystem = love.graphics.newParticleSystem(explosionParticle,64)
|
||||
eSystem:setParticleLifetime(0,0.7)
|
||||
eSystem:setLinearAcceleration(-2,-2,2,2)
|
||||
eSystem:setSpeed(2,8)
|
||||
eSystem:setRotation(1,7)
|
||||
eSystem:setSpin(1,2)
|
||||
eSystem:setRadialAcceleration(10,20)
|
||||
eSystem:setTangentialAcceleration(10,20)
|
||||
eSystem:setSizeVariation(0.9)
|
||||
eSystem:setSizes(0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 0.6, 0.1)
|
||||
eSystem:setColors(
|
||||
1,1,1,1,
|
||||
1,1,1,1,
|
||||
1,1,1,1,
|
||||
1,1,1,1,
|
||||
1,1,1,0.8,
|
||||
1,1,1,0.6,
|
||||
1,1,1,0.4,
|
||||
1,1,1,0.3
|
||||
)
|
||||
|
||||
GameScene.explosionObj = {angle=100, radius=100}
|
||||
GameScene.godsrayObj = {weight=0}
|
||||
|
||||
currentPlanet:init()
|
||||
currentPlanet:draw()
|
||||
end
|
||||
|
||||
function GameScene:update(dt)
|
||||
|
||||
if currentPlayer.death == false and currentPlanet.hasGeneratedMap == true then
|
||||
pSystem:update(dt)
|
||||
|
||||
GameScene:updateInput(dt)
|
||||
GameScene:updateBounds(dt)
|
||||
|
||||
if currentPlanet ~= nil then
|
||||
love.graphics.print("hebebs",100,100);
|
||||
currentPlanet.update(dt)
|
||||
|
||||
GameScene:checkCollisions()
|
||||
else
|
||||
eSystem:update(dt)
|
||||
end
|
||||
|
||||
currentPlanet:update(dt)
|
||||
self.updateEffects();
|
||||
end
|
||||
|
||||
function GameScene:draw()
|
||||
love.graphics.setColor(255,255,255, 1)
|
||||
love.graphics.setColor(1,1,1, 1)
|
||||
|
||||
if currentPlanet ~= nil and currentPlanet.canvas ~= nil then
|
||||
love.graphics.draw(currentPlanet.canvas,0,0)
|
||||
end
|
||||
|
||||
if currentPlayer.death == false then
|
||||
|
||||
love.graphics.setColor(1,1,1, 1)
|
||||
love.graphics.draw(pSystem, currentPlayer.px-2, currentPlayer.py)
|
||||
love.graphics.draw(pSystem, currentPlayer.px+2, currentPlayer.py)
|
||||
love.graphics.draw(
|
||||
|
@ -61,13 +97,14 @@ function GameScene:draw()
|
|||
currentPlayer.ship.image:getWidth()/2,
|
||||
currentPlayer.ship.image:getHeight()/2
|
||||
)
|
||||
|
||||
love.graphics.print(currentPlayer.px..","..currentPlayer.py.." s: " .. currentPlayer.speed .. " a: " ..currentPlayer.acc,10,10)
|
||||
else
|
||||
love.graphics.draw(eSystem, currentPlayer.px, currentPlayer.py)
|
||||
end
|
||||
end
|
||||
|
||||
function GameScene:drawHud()
|
||||
|
||||
love.graphics.setColor(255,255,255, 1)
|
||||
love.graphics.setColor(1,1,1, 1)
|
||||
love.graphics.draw( gameHud, 0, 600-66 )
|
||||
|
||||
love.graphics.setColor(255,255,255, 0.75)
|
||||
|
@ -77,6 +114,17 @@ function GameScene:drawHud()
|
|||
love.graphics.print( currentPlayer.name, 48, 550 )
|
||||
love.graphics.print( currentPlayer:getShipname(), 48, 566 )
|
||||
|
||||
love.graphics.print(
|
||||
"glbl: " .. currentPlayer.px..","..currentPlayer.py.." s: " .. currentPlayer.ship.speed .. " a: " ..currentPlayer.acc,
|
||||
10,10
|
||||
)
|
||||
|
||||
local deathval = "0"
|
||||
if currentPlayer.death then
|
||||
deathval = "1"
|
||||
end
|
||||
|
||||
love.graphics.print( "death: " .. deathval, 10, 24 )
|
||||
end
|
||||
|
||||
function GameScene:keypressed(key,unicode)
|
||||
|
@ -91,11 +139,12 @@ end
|
|||
|
||||
function GameScene:playerChanged(to)
|
||||
currentPlayer = to
|
||||
currentPlayer.px = windowWidth/2
|
||||
currentPlayer.py = windowHeight/2
|
||||
currentPlayer.px = math.floor(windowWidth/2)
|
||||
currentPlayer.py = math.floor(windowHeight/2)
|
||||
currentPlayer.rot = 0
|
||||
currentPlayer.acc = 0
|
||||
currentPlayer.bounds = { x1= 20, y1= 20, x2= windowWidth-20, y2= windowHeight - 86}
|
||||
currentPlayer.death = false
|
||||
end
|
||||
|
||||
function GameScene:updateInput(dt)
|
||||
|
@ -143,9 +192,9 @@ function GameScene:updateInput(dt)
|
|||
end
|
||||
|
||||
if isUp or isDown or isLeft or isRight then
|
||||
currentPlayer.acc = currentPlayer.acc + currentPlayer.accIncr
|
||||
currentPlayer.acc = currentPlayer.acc + currentPlayer.ship.accIncr
|
||||
elseif currentPlayer.acc > 0 then
|
||||
currentPlayer.acc = currentPlayer.acc - currentPlayer.accIncr
|
||||
currentPlayer.acc = currentPlayer.acc - currentPlayer.ship.accIncr
|
||||
end
|
||||
|
||||
currentPlayer.acc = math.clamp(0, currentPlayer.acc, 1)
|
||||
|
@ -156,24 +205,79 @@ function GameScene:updateInput(dt)
|
|||
end
|
||||
|
||||
if isUp then
|
||||
currentPlayer.py = currentPlayer.py - (currentPlayer.speed*currentPlayer.acc)
|
||||
currentPlayer.py = math.floor(currentPlayer.py - (currentPlayer.ship.speed*currentPlayer.acc))
|
||||
end
|
||||
|
||||
if isDown then
|
||||
currentPlayer.py = currentPlayer.py + (currentPlayer.speed*currentPlayer.acc)
|
||||
currentPlayer.py = math.floor(currentPlayer.py + (currentPlayer.ship.speed*currentPlayer.acc))
|
||||
end
|
||||
|
||||
if isLeft then
|
||||
currentPlayer.px = currentPlayer.px - (currentPlayer.speed*currentPlayer.acc)
|
||||
currentPlayer.px = math.floor(currentPlayer.px - (currentPlayer.ship.speed*currentPlayer.acc))
|
||||
end
|
||||
|
||||
if isRight then
|
||||
currentPlayer.px = currentPlayer.px + (currentPlayer.speed*currentPlayer.acc)
|
||||
currentPlayer.px = math.floor(currentPlayer.px + (currentPlayer.ship.speed*currentPlayer.acc))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function GameScene:updateBounds(dt)
|
||||
currentPlayer.px = math.clamp( currentPlayer.bounds.x1, currentPlayer.px, currentPlayer.bounds.x2 )
|
||||
currentPlayer.py = math.clamp( currentPlayer.bounds.y1, currentPlayer.py, currentPlayer.bounds.y2 )
|
||||
currentPlayer.px = math.floor(math.clamp( currentPlayer.bounds.x1, currentPlayer.px, currentPlayer.bounds.x2 ))
|
||||
currentPlayer.py = math.floor(math.clamp( currentPlayer.bounds.y1, currentPlayer.py, currentPlayer.bounds.y2 ))
|
||||
end
|
||||
|
||||
function GameScene:checkCollisions()
|
||||
-- Get basic alpha blended collision
|
||||
local cp = currentPlanet.canvas:newImageData( nil, nil, currentPlayer.px, currentPlayer.py, 1, 1):getPixel( 0,0 )
|
||||
if cp == 0 then
|
||||
currentPlayer.death = true
|
||||
self:generateExplosion( currentPlayer.px, currentPlayer.py )
|
||||
end
|
||||
end
|
||||
|
||||
function GameScene:generateExplosion(px,py)
|
||||
GameScene:generateExplosionSound(px,py)
|
||||
GameScene.explosionObj = {angle=100, radius=100}
|
||||
GameScene.godsrayObj = {weight=0}
|
||||
|
||||
flux.to(GameScene.explosionObj, 0.5, {angle= 100, radius=1600}):ease("quintout"):after( GameScene.explosionObj, 0.5, { angle= 100, radius= 100 })
|
||||
flux.to(GameScene.godsrayObj, 0.5, {weight=100}):ease("quintout"):after( GameScene.godsrayObj, 0.5, { weight=1 })
|
||||
|
||||
eSystem:emit(32)
|
||||
end
|
||||
|
||||
function GameScene:updateEffects()
|
||||
effect.chromasep.angle= math.floor(GameScene.explosionObj.angle/100)
|
||||
effect.chromasep.radius= math.floor(GameScene.explosionObj.radius/100)
|
||||
effect.godsray.weight= GameScene.godsrayObj.weight/100
|
||||
end
|
||||
|
||||
function GameScene:generateExplosionSound(px,py)
|
||||
local sound = sfxr.newSound()
|
||||
sound:resetParameters()
|
||||
sound.waveform = sfxr.WAVEFORM.NOISE
|
||||
sound.frequency.start = GameScene:variance(0.19907648104897,150)
|
||||
sound.frequency.slide = -0.057634852747835
|
||||
sound.repeatspeed = 0
|
||||
sound.envelope.attack = 0
|
||||
sound.envelope.sustain = GameScene:variance(0.30484231377123, 150)
|
||||
sound.envelope.punch = GameScene:variance(0.7393770288859, 150)
|
||||
sound.envelope.decay = 0.43495283918775
|
||||
sound.phaser.offset = GameScene:variance(0.53418301267674, 150)
|
||||
sound.phaser.sweep = -0.26648187020582
|
||||
sound.vibrato.depth = GameScene:variance(0.24860915303688, 150)
|
||||
sound.vibrato.speed = 0.44703997451237
|
||||
sound.change.speed = 0.83105037145914
|
||||
sound.change.amount = -0.66873272021076
|
||||
|
||||
local soundData = sound:generateSoundData()
|
||||
local source = love.audio.newSource(soundData)
|
||||
source:setVolume(2)
|
||||
source:setPosition(px,py)
|
||||
source:play()
|
||||
end
|
||||
|
||||
function GameScene:variance(seed, variance)
|
||||
return seed * ((math.random( 100 - (variance/2), 100 + (variance/2)))/100)
|
||||
end
|
|
@ -4,4 +4,6 @@ function Blackstar5:new()
|
|||
Blackstar5.super.new(self)
|
||||
self.name = "Blackstar 5";
|
||||
self.image = nil
|
||||
self.speed = 5
|
||||
self.accIncr = 0.1
|
||||
end
|
||||
|
|
|
@ -4,4 +4,6 @@ function Decorator:new()
|
|||
Decorator.super.new(self)
|
||||
self.name = "The Decorator";
|
||||
self.image = nil
|
||||
self.speed = 6
|
||||
self.accIncr = 0.2
|
||||
end
|
||||
|
|
|
@ -4,4 +4,6 @@ function ExcaliburIV:new()
|
|||
ExcaliburIV.super.new(self)
|
||||
self.name = "Excalibur IV";
|
||||
self.image = nil
|
||||
self.speed = 4
|
||||
self.accIncr = 0.3
|
||||
end
|
||||
|
|
224
vendor/flux.lua
vendored
Normal file
224
vendor/flux.lua
vendored
Normal file
|
@ -0,0 +1,224 @@
|
|||
--
|
||||
-- flux
|
||||
--
|
||||
-- Copyright (c) 2016 rxi
|
||||
--
|
||||
-- This library is free software; you can redistribute it and/or modify it
|
||||
-- under the terms of the MIT license. See LICENSE for details.
|
||||
--
|
||||
|
||||
local flux = { _version = "0.1.5" }
|
||||
flux.__index = flux
|
||||
|
||||
flux.tweens = {}
|
||||
flux.easing = { linear = function(p) return p end }
|
||||
|
||||
local easing = {
|
||||
quad = "p * p",
|
||||
cubic = "p * p * p",
|
||||
quart = "p * p * p * p",
|
||||
quint = "p * p * p * p * p",
|
||||
expo = "2 ^ (10 * (p - 1))",
|
||||
sine = "-math.cos(p * (math.pi * .5)) + 1",
|
||||
circ = "-(math.sqrt(1 - (p * p)) - 1)",
|
||||
back = "p * p * (2.7 * p - 1.7)",
|
||||
elastic = "-(2^(10 * (p - 1)) * math.sin((p - 1.075) * (math.pi * 2) / .3))"
|
||||
}
|
||||
|
||||
local makefunc = function(str, expr)
|
||||
local load = loadstring or load
|
||||
return load("return function(p) " .. str:gsub("%$e", expr) .. " end")()
|
||||
end
|
||||
|
||||
for k, v in pairs(easing) do
|
||||
flux.easing[k .. "in"] = makefunc("return $e", v)
|
||||
flux.easing[k .. "out"] = makefunc([[
|
||||
p = 1 - p
|
||||
return 1 - ($e)
|
||||
]], v)
|
||||
flux.easing[k .. "inout"] = makefunc([[
|
||||
p = p * 2
|
||||
if p < 1 then
|
||||
return .5 * ($e)
|
||||
else
|
||||
p = 2 - p
|
||||
return .5 * (1 - ($e)) + .5
|
||||
end
|
||||
]], v)
|
||||
end
|
||||
|
||||
|
||||
|
||||
local tween = {}
|
||||
tween.__index = tween
|
||||
|
||||
local function makefsetter(field)
|
||||
return function(self, x)
|
||||
local mt = getmetatable(x)
|
||||
if type(x) ~= "function" and not (mt and mt.__call) then
|
||||
error("expected function or callable", 2)
|
||||
end
|
||||
local old = self[field]
|
||||
self[field] = old and function() old() x() end or x
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
local function makesetter(field, checkfn, errmsg)
|
||||
return function(self, x)
|
||||
if checkfn and not checkfn(x) then
|
||||
error(errmsg:gsub("%$x", tostring(x)), 2)
|
||||
end
|
||||
self[field] = x
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
tween.ease = makesetter("_ease",
|
||||
function(x) return flux.easing[x] end,
|
||||
"bad easing type '$x'")
|
||||
tween.delay = makesetter("_delay",
|
||||
function(x) return type(x) == "number" end,
|
||||
"bad delay time; expected number")
|
||||
tween.onstart = makefsetter("_onstart")
|
||||
tween.onupdate = makefsetter("_onupdate")
|
||||
tween.oncomplete = makefsetter("_oncomplete")
|
||||
|
||||
|
||||
function tween.new(obj, time, vars)
|
||||
local self = setmetatable({}, tween)
|
||||
self.obj = obj
|
||||
self.rate = time > 0 and 1 / time or 0
|
||||
self.progress = time > 0 and 0 or 1
|
||||
self._delay = 0
|
||||
self._ease = "quadout"
|
||||
self.vars = {}
|
||||
for k, v in pairs(vars) do
|
||||
if type(v) ~= "number" then
|
||||
error("bad value for key '" .. k .. "'; expected number")
|
||||
end
|
||||
self.vars[k] = v
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
function tween:init()
|
||||
for k, v in pairs(self.vars) do
|
||||
local x = self.obj[k]
|
||||
if type(x) ~= "number" then
|
||||
error("bad value on object key '" .. k .. "'; expected number")
|
||||
end
|
||||
self.vars[k] = { start = x, diff = v - x }
|
||||
end
|
||||
self.inited = true
|
||||
end
|
||||
|
||||
|
||||
function tween:after(...)
|
||||
local t
|
||||
if select("#", ...) == 2 then
|
||||
t = tween.new(self.obj, ...)
|
||||
else
|
||||
t = tween.new(...)
|
||||
end
|
||||
t.parent = self.parent
|
||||
self:oncomplete(function() flux.add(self.parent, t) end)
|
||||
return t
|
||||
end
|
||||
|
||||
|
||||
function tween:stop()
|
||||
flux.remove(self.parent, self)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function flux.group()
|
||||
return setmetatable({}, flux)
|
||||
end
|
||||
|
||||
|
||||
function flux:to(obj, time, vars)
|
||||
return flux.add(self, tween.new(obj, time, vars))
|
||||
end
|
||||
|
||||
|
||||
function flux:update(deltatime)
|
||||
for i = #self, 1, -1 do
|
||||
local t = self[i]
|
||||
if t._delay > 0 then
|
||||
t._delay = t._delay - deltatime
|
||||
else
|
||||
if not t.inited then
|
||||
flux.clear(self, t.obj, t.vars)
|
||||
t:init()
|
||||
end
|
||||
if t._onstart then
|
||||
t._onstart()
|
||||
t._onstart = nil
|
||||
end
|
||||
t.progress = t.progress + t.rate * deltatime
|
||||
local p = t.progress
|
||||
local x = p >= 1 and 1 or flux.easing[t._ease](p)
|
||||
for k, v in pairs(t.vars) do
|
||||
t.obj[k] = v.start + x * v.diff
|
||||
end
|
||||
if t._onupdate then t._onupdate() end
|
||||
if p >= 1 then
|
||||
flux.remove(self, i)
|
||||
if t._oncomplete then t._oncomplete() end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function flux:clear(obj, vars)
|
||||
for t in pairs(self[obj]) do
|
||||
if t.inited then
|
||||
for k in pairs(vars) do t.vars[k] = nil end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function flux:add(tween)
|
||||
-- Add to object table, create table if it does not exist
|
||||
local obj = tween.obj
|
||||
self[obj] = self[obj] or {}
|
||||
self[obj][tween] = true
|
||||
-- Add to array
|
||||
table.insert(self, tween)
|
||||
tween.parent = self
|
||||
return tween
|
||||
end
|
||||
|
||||
|
||||
function flux:remove(x)
|
||||
if type(x) == "number" then
|
||||
-- Remove from object table, destroy table if it is empty
|
||||
local obj = self[x].obj
|
||||
self[obj][self[x]] = nil
|
||||
if not next(self[obj]) then self[obj] = nil end
|
||||
-- Remove from array
|
||||
self[x] = self[#self]
|
||||
return table.remove(self)
|
||||
end
|
||||
for i, v in ipairs(self) do
|
||||
if v == x then
|
||||
return flux.remove(self, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
local bound = {
|
||||
to = function(...) return flux.to(flux.tweens, ...) end,
|
||||
update = function(...) return flux.update(flux.tweens, ...) end,
|
||||
remove = function(...) return flux.remove(flux.tweens, ...) end,
|
||||
}
|
||||
setmetatable(bound, flux)
|
||||
|
||||
return bound
|
1536
vendor/sfxr.lua
vendored
Normal file
1536
vendor/sfxr.lua
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue