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