your-own-drum/main.lua

243 lines
5.1 KiB
Lua

local love = love
local step = 1.0 / 120
local sitelenpona
local text
local marble
local wave
local DetectCollision
local sounds = {
}
local state
state = {
Reset = function()
state.beat = {}
state.startTime = love.timer.getTime()
state.currentBeat = 1
state.timeToSimulate = 0.0
end,
timeToSimulate = 0.0,
isGameStarted = false,
beatScoreThreshold = 1.0,
lastBeatScore = 0.0,
currentBeat = 1,
startTime = 0.0,
wave = {
x = { 1.0, 0.0, -0.5, 0.2, 0.4, 0.8, 0.3, 0.9, -0.4, 0.8, 0.5, 0.1, -0.9 },
dx = { 1.0, 0.0, -0.5, 0.2, 0.4, 0.8, 0.3, 0.9, -0.4, 0.8, 0.5, 0.1, -0.9 },
ddx = { 1.0, 0.0, -0.5, 0.2, 0.4, 0.8, 0.3, 0.9, -0.4, 0.8, 0.5, 0.1, -0.9 },
X = function(th) end,
DX = function(th) end,
DDX = function(th) end,
Draw = function() end,
AddImpulse = function( th, size ) end,
ImpactPoint = function( xi, yi, xf, yf )
local impact = { r = 0, th = 0, t = 0, x = 0, y = 0, dx = 0, dy = 0 }
return impact
end,
Update = function( dt ) end,
},
beat = {
t = nil,
mu = nil,
},
}
local function UpdateWindowTransform( w, h )
local d = math.min( w, h )
local r = love.graphics.get
local tf = love.math.newTransform()
local size = 3
tf:translate( w / 2, h / 2)
tf:scale( d / size, -d / size )
transform = tf
end
function love.load()
UpdateWindowTransform( love.graphics.getDimensions() )
love.graphics.setBackgroundColor( 245 / 255, 169 / 255, 184 / 255 ) --Trans pink.
--love.graphics.setBackgroundColor( 91 / 255, 206 / 255, 250 / 255 ) --Trans blue.
sounds.goodPing = love.audio.newSource("sounds/soundTest.ogg", "static")
sounds.badPing = love.audio.newSource("sounds/chime8.ogg", "static")
sitelenpona = assert( require "sitelenpona" )
text = assert( require "text" )
marble = assert( require "marble" )
wave = assert( require "wave" )
DetectCollision = assert ( require "collision" )
return state.Reset()
end
local function BeatScore( t )
local beat = state.beat
--Base case 1: first tap.
if not beat.t then
beat.t = t
return 2.0
end
local dt = t - beat.t
beat.t = t
--Base case 2: second tap.
if not beat.mu then
beat.mu = dt
return 2.0
end
--General case: update average beat length.
local WEIGHT = 0.25 --High number makes the last beat more significant.
local mu = ( 1.0 - WEIGHT ) * beat.mu + WEIGHT * dt
beat.mu = mu
--Safety: avoid a dbz.
if mu < 0.001 or dt < 0.001 then
return 0.0
--error( "DBZ! Beat length too small." )
end
--Calculate beat score.
local score = dt * dt / ( mu * mu )
local TOLERANCE = 1.04
if dt < mu then
return TOLERANCE * score
else
return TOLERANCE / score
end
end
local function OnVictory()
end
local function OnImpact( impact )
if not impact then return end
local score = BeatScore( impact.t )
--DEBUG
state.lastBeatScore = score
local sound
if score > state.beatScoreThreshold then
sound = sounds.goodPing
state.beatScoreThreshold = 1.0
state.currentBeat = state.currentBeat + 1
if state.currentBeat >= 120 then
return OnVictory()
end
else
sound = sounds.badPing
state.beatScoreThreshold = state.beatScoreThreshold - 0.05
end
love.audio.play( sound )
marble.OnImpact( impact )
wave.OnImpact( impact )
end
function love.draw()
--[[love.graphics.setColor(1.0, 1.0, 1.0)
love.graphics.print( state.beat.mu or 0, 0)
love.graphics.print( state.beat.t or 0, 0, 10)
love.graphics.print( state.beatScoreThreshold, 0, 20)
love.graphics.print( state.lastBeatScore, 0, 30 )]]
love.graphics.push( "transform" )
love.graphics.applyTransform( transform )
wave.Draw()
if debugRenderImpact then
love.graphics.setLineWidth( 0.01 )
love.graphics.setColor( 1, 0, 0, 0.5 ) --Red: Incoming
love.graphics.line(
debugRenderImpact.xi,
debugRenderImpact.yi,
debugRenderImpact.xf,
debugRenderImpact.yf)
love.graphics.setColor( 0, 1, 0, 0.5 ) --Green: Normal
love.graphics.line(
debugRenderImpact.xi,
debugRenderImpact.yi,
debugRenderImpact.xn,
debugRenderImpact.yn)
love.graphics.setColor( 0, 0, 1, 0.5 ) -- Blue: Outgoing
love.graphics.line(
debugRenderImpact.xi,
debugRenderImpact.yi,
debugRenderImpact.vxout,
debugRenderImpact.vyout)
end
love.graphics.pop()
sitelenpona.Draw( text.tok[state.currentBeat] )
marble.Draw()
end
function love.update( dt )
dt = dt + state.timeToSimulate
while dt > step do
marble.Integrate( step )
wave.Integrate( step )
OnImpact(
DetectCollision(
marble.Current(), marble.Next(),
wave.Current(), wave.Next() ))
marble.Update()
wave.Update()
dt = dt - step
end
state.timeToSimulate = dt
end
function love.keypressed( key, code, isRepeat )
if key == "escape" then return love.event.quit() end
if key == "return" then return OnImpact{ t = love.timer.getTime() } end
return marble.OnKey()
end
function love.keyreleased( key, code )
return marble.OnKey()
end
function love.resize( w, h )
UpdateWindowTransform( w, h )
if marble then marble.Resize() end
end