From 8bbc029c423d5785c6509c013164a13eaf1db6ae Mon Sep 17 00:00:00 2001 From: Sage Vaillancourt Date: Sun, 26 Jan 2025 23:24:41 -0500 Subject: [PATCH] Bigger background for panning across. Refactor out utils.lua --- src/images/game/grass.png | Bin 2915 -> 8999 bytes src/main.lua | 118 ++++++++++++++++++++------------------ src/utils.lua | 31 ++++++++++ 3 files changed, 92 insertions(+), 57 deletions(-) create mode 100644 src/utils.lua diff --git a/src/images/game/grass.png b/src/images/game/grass.png index ab545fbe3f36daa1efc78d0baa7a15106255f4b1..f19739de474c485862889a5e63a94cc292419f6b 100644 GIT binary patch literal 8999 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 Dfs3xs diff --git a/src/main.lua b/src/main.lua index 996fe1d..76d42e1 100644 --- a/src/main.lua +++ b/src/main.lua @@ -3,6 +3,7 @@ import 'CoreLibs/easing.lua' import 'CoreLibs/graphics.lua' import 'CoreLibs/object.lua' import 'CoreLibs/ui.lua' +import 'utils.lua' local gfx = playdate.graphics playdate.display.setRefreshRate(50) @@ -16,7 +17,10 @@ local playerImage = playerHighHat local secPerFrame = 0.1 local playerFrameElapsed = 0 -local backgroundPan = -240 +local backgroundPan = { + x = 0, + y = 0, +} local pitchFlyTimeMs = 2500 local ballStartY, endY = 90, 250 @@ -41,8 +45,8 @@ local batTipX = 0 local batTipY = 0 local MODES = { - batting = 0, - running = 1 + batting = {}, + running = {} } local currentMode = MODES.batting @@ -53,7 +57,7 @@ local hitMult = 10 local deltaTime = 0 -local basePositions = { +local bases = { first = { x = screenW * 0.93, y = screenH * 0.52 }, second = { x = screenW * 0.47, y = screenH * 0.19 }, third = { x = screenW * 0.03, y = screenH * 0.52 }, @@ -85,8 +89,8 @@ function resetFielderPositions() end resetFielderPositions() -local playerStartingX = basePositions.home.x - 40 -local playerStartingY = basePositions.home.y - 3 +local playerStartingX = bases.home.x - 40 +local playerStartingY = bases.home.y - 3 local player = { x = playerStartingX, y = playerStartingY, @@ -109,10 +113,6 @@ function throwBall(destX, destY) hitAnimatorX = gfx.animator.new(throwFlyTime, ballX, destX, playdate.easingFunctions.linear) end -function getNextThrowTarget() - return basePositions.first.x, basePositions.first.y -end - function pitch() pitchAnimator:reset() resetFielderPositions() @@ -121,6 +121,9 @@ function pitch() ballX = 200 currentMode = MODES.batting + backgroundPan.y = 0 + backgroundPan.x = 0 + -- TODO: Add new runners, instead runners = {} player.x = playerStartingX @@ -151,25 +154,6 @@ local pitchClockSec = 99 local elapsedTime = 0 local crankChange -function ballPassedThruBat(ballX, ballY, batBaseX, batBaseY, batTipX, batTipY) - -- This check currently assumes right-handedness. - -- I.e. it assumes the ball is to the right of batBaseX - if ballX < batBaseX or ballX > batTipX or ballY > screenH then - return false - end - - local m = (batTipY - batBaseY) / (batTipX - batBaseX) - - -- y = mx + b - -- b = y1 - (m * x1) - local b = batBaseY - (m * batBaseX) - local yOnLine = (m * ballX) + b - local yP = ballY - local yDelta = yOnLine - yP - - return yDelta <= 0 -end - function updateInfield() if ballDestX == nil or ballDestY == nil then return @@ -200,7 +184,15 @@ function updateRunners() if runner.nextBase then local nb = runner.nextBase local x, y, distance = normalizeVector(runner.x, runner.y, nb.x, nb.y) - if distance > 1 then + runner.hasArrived = distance <= 1 + + if runner.hasArrived then + -- if runner.onArrive then + -- runner.onArrive() + -- end + runner.targetX = nil + runner.targetY = nil + else local mult = 1 if crankChange < 0 then mult = -1 @@ -208,31 +200,14 @@ function updateRunners() mult = (mult * runnerSpeed * deltaTime) + (crankChange / 20) runner.x -= x * mult runner.y -= y * mult - else - if runner.onArrive then - runner.onArrive() - end - runner.targetX = nil - runner.targetY = nil end end end end -function normalizeVector(x1, y1, x2, y2) - local distance, a, b = distanceBetween(x1, y1, x2, y2) - return a / distance, b / distance, distance -end - -function distanceBetween(x1, y1, x2, y2) - local a = x1 - x2 - local b = y1 - y2 - return math.sqrt((a*a) + (b*b)), a, b -end - function getNearestFielder(x, y) local nearestFielder, nearestDistance = nil, nil - for title,fielder in pairs(fielders) do + for _, fielder in pairs(fielders) do if nearestFielder == nil then nearestFielder = fielder nearestDistance = distanceBetween(fielder.x, fielder.y, x, y) @@ -256,6 +231,15 @@ function throwArrivedBeforeRunner() return false end +function getForcedOutTargets() + return { bases.first } +end + +function getNextThrowTarget() + local targets = getForcedOutTargets() + return targets[1].x, targets[1].y +end + function updateGameState() deltaTime = playdate.getElapsedTime() playdate.resetElapsedTime() @@ -281,7 +265,7 @@ function updateGameState() crankChange, acceleratedChange = playdate.getCrankChange() if currentMode == MODES.batting and acceleratedChange >= 0 and - ballPassedThruBat(ballX, ballY, batBaseX, batBaseY, batTipX, batTipY) then + pointDirectlyUnderLine(ballX, ballY, batBaseX, batBaseY, batTipX, batTipY, screenH) then ballAngle = batAngle + math.rad(90) mult = math.abs(acceleratedChange / 15) @@ -301,10 +285,10 @@ function updateGameState() throwBall(getNextThrowTarget()) chasingFielder.onArrive = nil end - fielders.first.targetX = basePositions.first.x - fielders.first.targetY = basePositions.first.y + fielders.first.targetX = bases.first.x + fielders.first.targetY = bases.first.y currentMode = MODES.running - player.nextBase = basePositions.first + player.nextBase = bases.first runners[#runners+1] = player end @@ -312,32 +296,52 @@ function updateGameState() updateRunners() updateInfield() end + + -- TODO: Show baserunning minimap when panning? + local ballBuffer = 5 + if ballY < ballBuffer then + backgroundPan.y = math.max(ballBuffer, -1 * (ballY - ballBuffer)) + else backgroundPan.y = 0 + end + if ballX < ballBuffer then + backgroundPan.x = math.max(-400, -1 * (ballX - ballBuffer)) + elseif ballX > (screenW - ballBuffer) then + backgroundPan.x = math.min(800, -1 * (ballX - ballBuffer)) + end + + if ballX > 0 and ballX < (screenW - ballBuffer) then + backgroundPan.x = 0 + end end function playdate.update() updateGameState() - grassBackground:draw(0, backgroundPan) + gfx.clear() + grassBackground:draw(backgroundPan.x - 400, backgroundPan.y - 240) gfx.setColor(gfx.kColorBlack) gfx.setLineWidth(2) - gfx.drawCircleAtPoint(ballX, ballY, ballSize) + gfx.drawCircleAtPoint(ballX + backgroundPan.x, ballY + backgroundPan.y, ballSize) for title,fielder in pairs(fielders) do - gfx.fillRect(fielder.x, fielder.y, 14, 25) + gfx.fillRect(fielder.x + backgroundPan.x, fielder.y + backgroundPan.y, 14, 25) end gfx.setLineWidth(5) if currentMode == MODES.batting then - gfx.drawLine(batBaseX, batBaseY, batTipX, batTipY) + gfx.drawLine( + batBaseX + backgroundPan.x, batBaseY + backgroundPan.y, + batTipX + backgroundPan.x, batTipY + backgroundPan.y + ) end if playdate.isCrankDocked() then playdate.ui.crankIndicator:draw() end - playerImage:draw(player.x, player.y) + playerImage:draw(player.x + backgroundPan.x, player.y + backgroundPan.y) -- TODO: Use gfx.animation.blinker instead if currentMode == MODES.running and playerFrameElapsed > secPerFrame then diff --git a/src/utils.lua b/src/utils.lua new file mode 100644 index 0000000..f53fff3 --- /dev/null +++ b/src/utils.lua @@ -0,0 +1,31 @@ +--- Returns the normalized vector as two values, plus the distance between the given points. +function normalizeVector(x1, y1, x2, y2) + local distance, a, b = distanceBetween(x1, y1, x2, y2) + return a / distance, b / distance, distance +end + +function distanceBetween(x1, y1, x2, y2) + local a = x1 - x2 + local b = y1 - y2 + return math.sqrt((a*a) + (b*b)), a, b +end + +function pointDirectlyUnderLine(pointX, pointY, lineX1, lineY1, lineX2, lineY2, bottomBound) + -- This check currently assumes right-handedness. + -- I.e. it assumes the ball is to the right of batBaseX + if pointX < lineX1 or pointX > lineX2 or pointY > bottomBound then + return false + end + + local m = (lineY2 - lineY1) / (lineX2 - lineX1) + + -- y = mx + b + -- b = y1 - (m * x1) + local b = lineY1 - (m * lineX1) + local yOnLine = (m * pointX) + b + local yP = pointY + local yDelta = yOnLine - yP + + return yDelta <= 0 +end +