From 25a3047a109c7b0876d819dc4891b26700f0fe77 Mon Sep 17 00:00:00 2001 From: yaw-man Date: Sun, 15 Jan 2023 22:38:15 -0400 Subject: [PATCH] Final FINAL physics tweaks. Game is done. Doing audio only until deadline. --- audio.lua | 72 +++++++++++++++++++++++++++++++++++++------------ main.lua | 12 ++++----- marble.lua | 57 ++++++++++++++++++++------------------- sitelenpona.lua | 4 +-- text.lua | 4 ++- 5 files changed, 95 insertions(+), 54 deletions(-) diff --git a/audio.lua b/audio.lua index 14b2318..8ee21a9 100644 --- a/audio.lua +++ b/audio.lua @@ -1,8 +1,9 @@ local love = love local passChimes = {} local failChimes = {} +local wineChimes = {} local drones = {} -local N = 8 +local N = 12 love.audio.setDistanceModel( "exponentclamped" ) @@ -13,50 +14,70 @@ local function StartDrones() decaytime = 20} ) - + drones.fuck = love.audio.newSource("sounds/noiseloop.flac", "static" ) drones.bass = love.audio.newSource("sounds/drone.flac", "stream") drones.alto = love.audio.newSource("sounds/drone.flac", "stream") + drones.bass:setVolume( 0 ) - drones.bass:setPitch( 0.125 ) - drones.alto:setVolume( 0 ) drones.bass:setPitch( 0.25 ) drones.bass:setEffect( "droneReverb", true ) - drones.alto:setEffect( "droneReverb", true ) drones.bass:stop() + + drones.alto:setVolume( 0 ) + drones.alto:setPitch( 2 ) + drones.alto:setEffect( "droneReverb", true ) drones.alto:stop() - + + drones.fuck:setVolume( 0 ) + drones.fuck:setPitch( 0.125 ) + drones.fuck:setEffect( "droneReverb", true ) + drones.fuck:stop() + love.audio.play( drones.bass ) love.audio.play( drones.alto ) + love.audio.play( drones.fuck ) end love.audio.setEffect( "passChimeReverb", { type = "reverb", - volume = 1.0, } ) + volume = 1.0, + gain = 1.0,} ) +local wineChime = love.audio.newSource("sounds/chimewinedolce.flac", "static") +wineChime:setEffect( "passChimeReverb", true ) local passChime = love.audio.newSource("sounds/chimeb.flac", "static") passChime:setEffect( "passChimeReverb", true ) local failChime = love.audio.newSource("sounds/chime.flac", "static") failChime:setEffect( "passChimeReverb", true ) for i = 1, N do + wineChimes[i] = wineChime:clone() passChimes[i] = passChime:clone() failChimes[i] = failChime:clone() end local idxNextPassChime = 1 local idxNextFailChime = 1 -local function GetNextPassChime( pass ) +local idxNextWineChime = 1 +local function GetNextPassChime( ) idxNextPassChime = idxNextPassChime % N + 1 return passChimes[ idxNextPassChime ] end -local function GetNextFailChime( pass ) +local function GetNextFailChime( ) idxNextFailChime = idxNextFailChime % N + 1 return failChimes[ idxNextFailChime ] end +local function GetNextWineChime( ) + idxNextWineChime = idxNextWineChime % N + 1 + return wineChimes[ idxNextWineChime ] +end + local pitches = { + 1/2, + 3/4, 1, 2/3, 3/2, @@ -69,7 +90,7 @@ local pitches = local function GetPitch( th ) th = 0.5 + 0.5 * th / math.pi - return pitches[ 1 + math.floor( th * 7 )] + return pitches[ 1 + math.floor( th * 9 )] end local function OnImpact( impact, score, pass, level ) @@ -83,7 +104,8 @@ local function OnImpact( impact, score, pass, level ) love.audio.setEffect( "passChimeReverb", { type = "reverb", volume = 1.0, - gain = 0.1 + level / 200} ) + gain = 0.1 + 0.9 * level / 120, + highgain = 0.3,} ) end @@ -94,8 +116,8 @@ local function OnImpact( impact, score, pass, level ) local chime = pass and GetNextPassChime() or GetNextFailChime() chime:setPitch( GetPitch( th ) ) chime:setPosition( r * math.cos( th ), r * math.sin( th ) ) - chime:setVolume( 0.1 + level / 200 ) - local highgain = math.max( 0, math.min( score, 1.0 ) - (pass and 0.0 or 0.9)) + chime:setVolume( 0.1 + 0.9 * level / 120.0 ) + local highgain = math.max( 0, math.min( score, 1.0 ) - (pass and 0.5 or 0.9)) chime:setFilter{ type = "lowpass", volume = 0.5 * impact.speed, @@ -103,6 +125,14 @@ local function OnImpact( impact, score, pass, level ) } love.audio.stop( chime ) love.audio.play( chime ) + + local wineChime = GetNextWineChime() + wineChime:setPitch( GetPitch( th ) ) + wineChime:setPosition( love.math.random(), love.math.random() ) + wineChime:setVolume( impact.speed * math.max( 0.0, level / 60.0 - 0.5 ) ) + + love.audio.stop( wineChime ) + love.audio.play( wineChime ) end @@ -110,21 +140,29 @@ local function OnVictory( ) love.audio.setEffect( "passChimeReverb", { type = "reverb", volume = 1.0, - decaytime = 20,} ) + decaytime = 20, + lategain = 9.5, + gain = 1.0, + } ) love.audio.setEffect( "droneReverb", { type = "reverb", volume = 1.0, - decaytime = 20,} ) + decaytime = 20, + lategain = 10, + gain = 1.0,} ) end --score is the hypothetical "beat score" that would be attained --if an impact took place at this instant. local function Update( score, level ) + + if level > 2 then - drones.bass:setVolume( 0.5 * math.sqrt( score ) * (level / 120) ) - drones.alto:setVolume( 0.3 * score * ( level / 120 )) + level = level / 120.0 + drones.bass:setVolume( 0.5 * math.sqrt( score ) * level ) + drones.alto:setVolume( 0.3 * score * level * level) end end diff --git a/main.lua b/main.lua index f85cdae..83af7a0 100644 --- a/main.lua +++ b/main.lua @@ -75,7 +75,7 @@ OnImpact = function( impact ) particles:emit( 50 * score * score ) audio.OnImpact( impact, score, pass, state.currentBeat ) - marble.OnImpact( impact ) + marble.OnImpact( impact, state.currentBeat ) wave.OnImpact( impact, state.currentBeat ) end local _OnImpact = OnImpact @@ -191,19 +191,17 @@ OnVictory = function() particles:setParticleLifetime( 0, 30 ) particles:setSizes( 0.001, 0.0001, 0.0005 ) particles:setColors( - 1, 1, 1, 1, 245 / 255, 169 / 255, 184 / 255, 1, 1, 1, 1, 1, - 1, 1, 1, 0, - 0, 0, 0, 1, 245 / 255, 169 / 255, 184 / 255, 1, - 0, 0, 0, 1, + 1, 1, 1, 0, + 245 / 255, 169 / 255, 184 / 255, 1, 1, 1, 1, 0 ) particles:setPosition( 0, 0 ) particles:setEmissionArea( "normal", 0.5, 0.5, 0, true ) particles:emit( 500 ) - particles:setEmissionArea( "normal", 0.1, 0.1, 0, true ) + particles:setEmissionArea( "normal", 0.01, 0.01, 0, true ) love.graphics.setCanvas( marble.Canvas() ) love.graphics.setCanvas() @@ -221,7 +219,7 @@ OnVictory = function() end local marblePos = marble.Current() - particles:emit( 10 ) + particles:emit( 1 ) particles:update( dt ) particles:moveTo( marblePos.x, marblePos.y ) end diff --git a/marble.lua b/marble.lua index dbf5d60..8550832 100644 --- a/marble.lua +++ b/marble.lua @@ -5,8 +5,8 @@ local oldBuffer = love.graphics.newCanvas() local newBuffer = love.graphics.newCanvas() local oldState, curState, newState -local INERTIA= 0.03 -local MAXSPEED = 3 +local INERTIA = 0.01 +local MAXSPEED = 6 local ddx, ddy = 0.0, 0.0 local function State( ) @@ -21,20 +21,19 @@ function marble.GetAcceleration( ) return ddx, ddy end function marble.Integrate( step ) newState.t = love.timer.getTime() - newState.dx = (1.0 - INERTIA -) * curState.dx + INERTIA - * ddx - newState.dy = (1.0 - INERTIA -) * curState.dy + INERTIA - * ddy + newState.dx = (1.0 - INERTIA) * curState.dx + INERTIA * ddx + newState.dy = (1.0 - INERTIA) * curState.dy + INERTIA * ddy newState.x = curState.x + newState.dx * step * MAXSPEED newState.y = curState.y + newState.dy * step * MAXSPEED end -function marble.OnImpact( impact ) +function marble.OnImpact( impact, level ) --Adjust current trajectory according to collision. if not impact.dt then return end + INERTIA = 0.05 - 0.04 * ( level / 120.0 ) + MAXSPEED = 2.0 + 4.0 * ( level / 120.0 ) + local x, y = impact.r * math.cos( impact.th ), impact.r * math.sin( impact.th ) local vx, vy = newState.dx, newState.dy --Velocity of particle going into collision. local unx, uny = math.cos( impact.normal ), math.sin( impact.normal ) --Outward-facing normal of wave. @@ -49,16 +48,16 @@ function marble.OnImpact( impact ) else uvx, uvy = vx / speed , vy / speed end - - - + + + --Get signed angle between normal and incoming velocity (both unit vectors) local dot = unx * uvy - uny * uvx - + --Fudge factor: apply an impulse inward so that you don't stick or slide on the wave. local inward = ( dot > 0 ) and dot or -dot inward = inward * inward * inward - + --Calculate the rotation matrix: --counterclockwise rotation by 2 * pi - 2 * arccos( n dot v ) local c, s = 1 - 2 * dot * dot, - 2 * dot * math.sqrt( 1 - dot * dot ) @@ -66,14 +65,14 @@ function marble.OnImpact( impact ) local vxout, vyout = inward * (- math.cos(impact.th) ) - (1.0 - inward) * ( vx * c - vy * s ), inward * (- math.sin(impact.th) ) - (1.0 - inward) * ( x * s + vy * c ) - + curState.x, curState.y = x, y curState.dx, curState.dy = vxout, vyout - + --[[debugRenderImpact = { xi = x, yi = y, xf = x - vx, yf = y - vy, xn = 0.2 * unx + x, yn = 0.2 * uny + y, vxout = x + vxout, vyout = y + vyout}]] - + return marble.Integrate( math.max( impact.dt , 1 / 120 ) ) --Hmm! Maybe this should be a fixed step instead for stability's sake. end @@ -90,14 +89,14 @@ end function marble.OnKey() ddx = (love.keyboard.isScancodeDown( "d" ) and 1.0 or 0.0) - (love.keyboard.isScancodeDown( "a" ) and 1.0 or 0.0) ddy = (love.keyboard.isScancodeDown( "w" ) and 1.0 or 0.0) - (love.keyboard.isScancodeDown( "s" ) and 1.0 or 0.0) - + local n = math.sqrt( ddx * ddx + ddy * ddy ) if n < 0.001 then return end ddx, ddy = ddx / n, ddy / n end function marble.OnVictory() - + --[[marble.Draw = function() --Extrapolate forward for slightly smoother rendering. @@ -125,7 +124,7 @@ function marble.Draw() --Extrapolate forward for slightly smoother rendering. local dt = love.timer.getTime() - curState.t marble.Integrate( dt + 1 / 60.0 ) - + local xp, yp = transform:transformPoint( oldState.x, oldState.y ) local xc, yc = transform:transformPoint( curState.x, curState.y ) local xn, yn = transform:transformPoint( newState.x, newState.y ) @@ -133,7 +132,7 @@ function marble.Draw() love.graphics.setCanvas( newBuffer ) love.graphics.setColor( 1.0, 1.0, 1.0 , 0.99 ) -- White. love.graphics.draw( oldBuffer ) --Time-dependent fade: overlay canvas over itself. - + --Render latest segment in trail. love.graphics.setColor( 245 / 255, 169 / 255, 184 / 255, 1.0 ) --Trans pink. --love.graphics.line( xi, yi, xf, yf ) @@ -143,17 +142,17 @@ function marble.Draw() love.graphics.setLineWidth( 8.0 ) love.graphics.line( xp, yp, xc, yc, xn, yn) love.graphics.circle( "fill", xn, yn, 4.0 ) - + love.graphics.setCanvas( oldBuffer ) love.graphics.clear( 1.0, 1.0, 1.0, 0.0 ) - + --Render circle directly to screen. love.graphics.setCanvas() love.graphics.draw( newBuffer ) love.graphics.setColor( 1, 1, 1, 1.0 ) --White. love.graphics.setLineWidth( 1.0 ) --love.graphics.circle( "line", xn, yn, 4 ) - + oldBuffer, newBuffer = newBuffer, oldBuffer end @@ -161,7 +160,7 @@ end marble._Draw = marble.Draw function marble.Impact( impact ) - + end --Window resize. @@ -169,11 +168,15 @@ function marble.Resize() newBuffer = love.graphics.newCanvas() --TODO: render oldBuffer to new newBuffer, but scaled down. oldBuffer = love.graphics.newCanvas() - + end -function marble.Reset() +function marble.Reset() + + INERTIA = 0.05 + MAXSPEED = 2.0 + oldState, curState, newState = State(), State(), State() marble.Resize() marble.Draw = marble._Draw diff --git a/sitelenpona.lua b/sitelenpona.lua index aeec7ec..7d57130 100644 --- a/sitelenpona.lua +++ b/sitelenpona.lua @@ -15,8 +15,8 @@ sp.Draw = function( t ) if #t == 1 then love.graphics.draw( sp[t[1]] or sp.pilin, cx - 128, cy - 128 ) elseif #t == 2 then - love.graphics.draw( sp[t[1]] or sp.pilin, cx - 128, cy - 64, 0, 0.5, 0.5 ) - love.graphics.draw( sp[t[2]] or sp.pilin, cx, cy - 64, 0, 0.5, 0.5 ) + love.graphics.draw( sp[t[1]] or sp.pilin, cx - 144, cy - 96, 0, 0.75, 0.75 ) + love.graphics.draw( sp[t[2]] or sp.pilin, cx - 16, cy - 96, 0, 0.75, 0.75 ) elseif #t == 3 then love.graphics.draw( sp[t[1]] or sp.pilin, cx - 128, cy - 64, 0, 0.5, 0.5 ) love.graphics.draw( sp[t[1]] or sp.pilin, cx - 128, cy - 64, 0, 0.5, 0.5 ) diff --git a/text.lua b/text.lua index 5b5241f..6e0b192 100644 --- a/text.lua +++ b/text.lua @@ -39,9 +39,11 @@ for foot in s:gmatch( ".-%-" ) do local j = 1 for w in foot:gmatch( [["]] ) do + word[j] = isTe and "te" or "to" isTe = not( isTe ) j = j + 1 + end for w in foot:gmatch( "%a+" ) do @@ -59,7 +61,7 @@ local function Draw( beat ) if beat == 1 then love.graphics.setColor(0.0, 0.0, 0.0, 1.0) love.graphics.printf( "wasd.space", - 0, 0.5 * love.graphics.getHeight(), + 0, 0, love.graphics.getWidth(), "center" )