From 5493f350df59de3ed572ecb1685a2892831fca3a Mon Sep 17 00:00:00 2001
From: Sage Vaillancourt <sage@sagev.space>
Date: Sun, 26 Jan 2025 21:34:19 -0500
Subject: [PATCH] Start up some simple baserunning.

---
 .gitignore                        |   1 +
 src/images/game/grass.png         | Bin 2241 -> 2915 bytes
 src/images/game/menu-image.png    | Bin 0 -> 11102 bytes
 src/images/game/player-lowhat.png | Bin 0 -> 711 bytes
 src/main.lua                      | 125 ++++++++++++++++++++++++------
 5 files changed, 104 insertions(+), 22 deletions(-)
 create mode 100644 src/images/game/menu-image.png
 create mode 100644 src/images/game/player-lowhat.png

diff --git a/.gitignore b/.gitignore
index e00b594..66f1578 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 *.pdx
+.idea
diff --git a/src/images/game/grass.png b/src/images/game/grass.png
index 4da3e6e1eb5618a0d93e26823e39d68bc5b3b354..ab545fbe3f36daa1efc78d0baa7a15106255f4b1 100644
GIT binary patch
delta 460
zcmX>o_*iU$7&qes4mJh`hVHr6yc-o~G8zKe3=BV=ch>_c&H|6fVg?31We{epSZZGe
z6l5>)^mS!_$tcYv$5f{?IdbxAMs+4m>&YTa4=3+s(yC`*Vrpn$P*7mt-~ckI&jT9^
zw*iCagk(L2Byn<+3z-}z$1!P5zQZI5^pXV-%Oq3ZBWQv1NNDl}CRM0?e8L#^9Z28&
cooO4ZNaKCeBN4g^0ibyDboFyt=akR{04cIdMgRZ+

delta 112
zcmaDXc2IDF7&pTQ4mJh`20a@irHzU+84dq40O5kY%O?W`ISV`@i-B^=Ak0{?)V>TT
z$X?><>&pI;QA$`w=*w6CxszWrsxz_8oGilhkm*3(=9#S9SViU+8b8^&Q=|o`oWax8
K&t;ucLK6UPLnAi;

diff --git a/src/images/game/menu-image.png b/src/images/game/menu-image.png
new file mode 100644
index 0000000000000000000000000000000000000000..baa6ddb1fc45d28669133aee5d4797bda87784ea
GIT binary patch
literal 11102
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

literal 0
HcmV?d00001

diff --git a/src/images/game/player-lowhat.png b/src/images/game/player-lowhat.png
new file mode 100644
index 0000000000000000000000000000000000000000..985867e065b135650bc751e00729dced5d051e81
GIT binary patch
literal 711
zcmV;&0yzDNP)<h;3K|Lk000e1NJLTq000&M001Zm1^@s6`os$60004mX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmP!xqvQ$>-Af*n*GGPF*1Q4z;lg(6f4wL+^7CNKSiCJjl7
zi=*ILaPVib>fqw6tAnc`2>yV$3r>nIQsR9{p+$@r9`ED4dk*j22MCP{)2yyIpy{@m
zPA0@`ZdL4gMF1lhL=*v;S;m|srQlm%_tZ^w7vov}eScQJnztAb5Q*c=Fm2)u;+aj`
z;Ji;9W+hoAJ|~_q>4L<MTvt4P<6LxE;F)1Flb$CI6N|+TRyvrKOpSP&IHGDg<qKJl
zRnA+SwMvb(?#W*m%Iho3T&FdLBo?s*2_h8KP(}qdVzld|SV+@(!pA@A`XzEH<SK)a
zV*yoYkX=9cAN-!JRhXLel0pff`^9lSqCn3s(5ySo_p#$NPk`VvaHY5X)dn#8NqW7l
zMUH@hZQ$a%ttorJ<qk0XWXPuMN<msep#Z#}(KqFQp<AGD&6`{69H$RJhGvzz0S*p<
z@gilf`@Flib8i3kwC48%XlinzGWX+!00006VoOIv0RI600RN!9r;`8x010qNS#tmY
zE+YT{E+YYWr9XB6000McNliru=>Z!7Gcn_k7Wn`G02y>eSad^gZEa<4bO1wgWnpw>
zWFU8GbZ8()Nlj2!fese{005s!L_t(Y$L&^I4!|G?vu5|dGW&8d3LE%fbCFMlN-GdT
zSj}MYB}*(C096?A4JoJx3!Px1xkzzkOJqwNKz*bEOo93R-Pu$rVk>>Nj53V*8IQKZ
zN>MAFf5uF0s@eSP^Abf#lJ9+9Z%1O}4EB{mLzx?ulFxc|yn#1xUCus3h#Qel9Vv}f
tb`z2w$XmK>?=oiUQb<OB)w;W09iOgYLp}J!*|`7!002ovPDHLkV1lX@FAM+x

literal 0
HcmV?d00001

diff --git a/src/main.lua b/src/main.lua
index 6cd6b2b..996fe1d 100644
--- a/src/main.lua
+++ b/src/main.lua
@@ -7,9 +7,16 @@ import 'CoreLibs/ui.lua'
 local gfx = playdate.graphics
 playdate.display.setRefreshRate(50)
 gfx.setBackgroundColor(gfx.kColorWhite)
+playdate.setMenuImage(gfx.image.new("images/game/menu-image.png"))
 
 local grassBackground = gfx.image.new("images/game/grass.png")
-local playerImage = gfx.image.new("images/game/player.png")
+local playerHighHat = gfx.image.new("images/game/player.png")
+local playerLowHat = gfx.image.new("images/game/player-lowhat.png")
+local playerImage = playerHighHat
+local secPerFrame = 0.1
+local playerFrameElapsed = 0
+
+local backgroundPan = -240
 
 local pitchFlyTimeMs = 2500
 local ballStartY, endY = 90, 250
@@ -26,7 +33,6 @@ local batBaseX, batBaseY = centerX - 34, 215
 local batLength = 45
 
 local ballY = ballStartY
-local lastBallY = ballY
 local ballX = 200
 local ballVelX, ballVelY = 0, 0
 local ballSize = 6
@@ -34,7 +40,6 @@ local ballSize = 6
 local batTipX = 0
 local batTipY = 0
 
-local hit = false
 local MODES = {
     batting = 0,
     running = 1
@@ -80,13 +85,17 @@ function resetFielderPositions()
 end
 resetFielderPositions()
 
+local playerStartingX = basePositions.home.x - 40
+local playerStartingY = basePositions.home.y - 3
 local player = {
-    x = basePositions.home.x - 40,
-    y = basePositions.home.y - 3,
+    x = playerStartingX,
+    y = playerStartingY,
     nextBase = nil,
     prevBase = nil,
 }
 
+local runners = { }
+
 function hitBall(destX, destY, hitFlyTime)
     ballSizeAnimator:reset(ballSizeMs)
     hitAnimatorY = gfx.animator.new(hitFlyTime, ballY, destY, playdate.easingFunctions.outQuint)
@@ -100,13 +109,22 @@ 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()
     ballVelX = 0
     ballVelY = 0
     ballX = 200
-    hit = false
+    currentMode = MODES.batting
+
+    -- TODO: Add new runners, instead
+    runners = {}
+    player.x = playerStartingX
+    player.y = playerStartingY
 end
 
 function playdate.AButtonDown()
@@ -131,6 +149,7 @@ end
 
 local pitchClockSec = 99
 local elapsedTime = 0
+local crankChange
 
 function ballPassedThruBat(ballX, ballY, batBaseX, batBaseY, batTipX, batTipY)
     -- This check currently assumes right-handedness.
@@ -152,22 +171,21 @@ function ballPassedThruBat(ballX, ballY, batBaseX, batBaseY, batTipX, batTipY)
 end
 
 function updateInfield()
-    if not hit or ballDestX == nil or ballDestY == nil then
+    if ballDestX == nil or ballDestY == nil then
         return
     end
 
-    local fielderSpeed = 50
+    local fielderSpeed = 40
     for title,fielder in pairs(fielders) do
         if fielder.targetX ~= nil and fielder.targetY ~= nil then
-            local distance, a, b = distanceBetween(fielder.x, fielder.y, fielder.targetX, fielder.targetY)
-            local normalizer = fielderSpeed / distance
+            local x, y, distance = normalizeVector(fielder.x, fielder.y, fielder.targetX, fielder.targetY)
 
             if distance > 1 then
-                fielder.x -= a * normalizer * deltaTime
-                fielder.y -= b * normalizer * deltaTime
+                fielder.x -= x * fielderSpeed * deltaTime
+                fielder.y -= y * fielderSpeed * deltaTime
             else
                 if fielder.onArrive then
-                    fielder.onArrive(fielder.targetX, fielder.targetY)
+                    fielder.onArrive()
                 end
                 fielder.targetX = nil
                 fielder.targetY = nil
@@ -176,6 +194,36 @@ function updateInfield()
     end
 end
 
+function updateRunners()
+    local runnerSpeed = 20
+    for i,runner in pairs(runners) do
+        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
+                local mult = 1
+                if crankChange < 0 then
+                    mult = -1
+                end
+                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
@@ -200,6 +248,14 @@ function getNearestFielder(x, y)
     return nearestFielder
 end
 
+function ballIsBeingThrown()
+    return false
+end
+
+function throwArrivedBeforeRunner()
+    return false
+end
+
 function updateGameState()
     deltaTime = playdate.getElapsedTime()
     playdate.resetElapsedTime()
@@ -210,7 +266,7 @@ function updateGameState()
         pitch()
     end
 
-    if hit then
+    if currentMode == MODES.running then
         ballX = hitAnimatorX:currentValue()
         ballY = hitAnimatorY:currentValue()
         ballSize = ballSizeAnimator:currentValue()
@@ -224,7 +280,7 @@ function updateGameState()
     batTipY = batBaseY + (batLength * math.cos(batAngle))
 
     crankChange, acceleratedChange = playdate.getCrankChange()
-    if hit == false and acceleratedChange >= 0 and
+    if currentMode == MODES.batting and acceleratedChange >= 0 and
       ballPassedThruBat(ballX, ballY, batBaseX, batBaseY, batTipX, batTipY) then
         ballAngle = batAngle + math.rad(90)
 
@@ -242,22 +298,26 @@ function updateGameState()
         chasingFielder.targetX = ballDestX
         chasingFielder.targetY = ballDestY
         chasingFielder.onArrive = function()
-            throwBall(basePositions.first.x, basePositions.first.y)
+            throwBall(getNextThrowTarget())
+            chasingFielder.onArrive = nil
         end
         fielders.first.targetX = basePositions.first.x
         fielders.first.targetY = basePositions.first.y
-        hit = true
+        currentMode = MODES.running
+        player.nextBase = basePositions.first
+        runners[#runners+1] = player
     end
-    lastBallY = ballY
 
-    updateInfield()
+    if currentMode == MODES.running then
+        updateRunners()
+        updateInfield()
+    end
 end
 
 function playdate.update()
     updateGameState()
 
-    grassBackground:draw(0, 0)
-    playerImage:draw(player.x, player.y)
+    grassBackground:draw(0, backgroundPan)
 
     gfx.setColor(gfx.kColorBlack)
     gfx.setLineWidth(2)
@@ -268,9 +328,30 @@ function playdate.update()
     end
 
     gfx.setLineWidth(5)
-    gfx.drawLine(batBaseX, batBaseY, batTipX, batTipY)
+
+    if currentMode == MODES.batting then
+        gfx.drawLine(batBaseX, batBaseY, batTipX, batTipY)
+    end
 
     if playdate.isCrankDocked() then
         playdate.ui.crankIndicator:draw()
     end
+
+    playerImage:draw(player.x, player.y)
+
+    -- TODO: Use gfx.animation.blinker instead
+    if currentMode == MODES.running and playerFrameElapsed > secPerFrame then
+        playerFrameElapsed = 0
+        if playerImage == playerHighHat then
+            playerImage = playerLowHat
+        else
+            playerImage = playerHighHat
+        end
+    else
+        playerFrameElapsed += deltaTime
+    end
+
+    -- for i,runner in pairs(runners) do
+    --     playerImage:draw(runner.x, runner.y)
+    -- end
 end