From 66e3d2bb0183750000718708d235951c8cdfe488 Mon Sep 17 00:00:00 2001 From: Sage Vaillancourt Date: Sun, 2 Feb 2025 13:32:22 -0500 Subject: [PATCH] Fielders can run the ball towards a base themselves. Ball can be heldBy a fielder. Fix likely bug in buildCache() and document it (including contemplating future removal). Add missing Full Circle font png. --- .../font-full-circle-table-12-15.png | Bin 0 -> 3137 bytes src/main.lua | 36 ++++++++++++------ src/utils.lua | 21 ++++++---- 3 files changed, 37 insertions(+), 20 deletions(-) create mode 100644 src/fonts/Full Circle/font-full-circle-table-12-15.png diff --git a/src/fonts/Full Circle/font-full-circle-table-12-15.png b/src/fonts/Full Circle/font-full-circle-table-12-15.png new file mode 100644 index 0000000000000000000000000000000000000000..017612298ba7d125f0f4cb01bc918fb377289de3 GIT binary patch literal 3137 zcmV-H48HS;P)Px=`$={?=*X>6>0eVfM@w{;M?C~i^_a2rp^7G6(o}-mG zTW|5LJn>aNi^sXz1331L zdC{Z7r&=m_ukWhZ6w3=GgBLKW*Syw6 z_|bUe$0*;ayTAe59D0LX&~j;uiv9{_si*?k9W@nXe;(vqi0iNE@%(zvPsiiHao{*` z95@af2aW?X4)C`K_#WrInAe<#^>D2k)okY(?c2-g^;M1s9r^%h zA}ml)aqkJrN_+9DwYN6Y(aQDoQjIO%cg^dJnKz2FvwC%iu?DM$u{?Tat;YWD?E{d4 z|5nX!Dt$amHhh-z6!-G?;@MN{JdKC}qd3-jc;-AjbGj-n<6})P9(5x%>{nUo5qnkU zAeQ`YjXnT&2tAWzcD0}6ZD-L^$ zMJ&R5Sm2}A2%f#Mw(5!X`e(ITm*FgLiq!`o1zOgQbFXmXt9m?KFGt5XB`Es??CC3! z1R!#+<_+4F!q7rpSXXN!H^fxAOE`T1v&h-{bdU>@}KWJ=R{1 zUcC0&y@xiwSM?%aHutJthvzu(j|2GW$)BLdlHUk)>(Lt}PooQAk zxXGz~B3{Ku7{B96C>llZJP2k37NeGimg^IiJ2M`dc@mub-l0L?uy zs~URT%Lb`9XE42bdhw=R^XTz6i#7sO&yMQ^PVIqFyqGs4>XvA-4*;8y+zMnKYnD^o zx9_b_^!D3*!Tfr|SA0?Yl7}FA0Crp)J0J#FGQ^-*tEWZNi*NDSyydqKj>YdjLk~6V zyiRuR)?8Ls3!mosTObRUpq(%89$@b3Rdr4Ewx0kX z&IWDeGcg&jR~O-<;Um1qjaY<__#>Vu9`Q%`UGZ5Rdd{KSzXI2*qZhwIV}--h<;BSLlw*K5KY`Ioe3U=& zh9J01n4F_1>Fwlh2)Jy63sC- zyXwuqgMU_^SFbvC53D_V^4hQi?Po0&5IGQTp5n|k(IpKYlP?08vO*|0J{W`|E&!AF$21( znJYcwOg!sqvBWVPHk&880&+Cr^`T+ErqQ>^r>V@+z@F;JO24H*o zsAl%bZaQMH64&ZS9BW#5?NQx(oZ7d_6XC#x9(b?hjrw_UZ$`yE=xTih(n9VZ2pH^K zM>$68R9?nW&5hu+M)#`i>@RlUT!@Pee}i`3PtcY3$!`8Gi$^{Ix*8ntao{*`95@af z2aW^Bf%`gu?`7V1v->Lk9A&-U_u{Qnv-Otmt&3rfrm&~}9RPz=hYkrpFu@Cam(gag(QN%)d|0AGAAlah=%&cb^=cx# zhlRdgd^A%pf7aXUF~aZFc=HnH83ySw(XzL^Jr##EcV3x3r_?wz;lSE}^M+zfS&*W+b64aBhKPm0xf@pCysh~ zj_`MlLqD~1mK9pbNiOBKIbfLga^zUCf*-x`-rXzIs}Dd3dQpNGLfgO0C>7DUZ(U&C z2%xnyubx-=S95pTau4_&e+!gd7`=d3JE*;NpXnfuYlhvOQw^EN%qf0{HuAIIjvh_U zyM6+ArqHnFP>TW3!rolj!qdr|#oDunBOkF?86$pVB_C>6@QrA=WsN=nYEngPFTTPF z%q*|gXBS&>Ep6bj_>5cmyjsn3uY8pntA{*xwK#j$zP9$`&#kXOo;hCZDx8bayJ2<^Qr5McQfV0M~;wcF~peF}b`%gYJ%I*!~ zGK`8PzQwCG+xGeuXj_v*ywm}`ftC^*vg!?O%9_Vryv@cQp!F5Vt2wdzI&iC->%KPq bU)lcvr~5wcbwSCg00000NkvXXu0mjfsupYa literal 0 HcmV?d00001 diff --git a/src/main.lua b/src/main.lua index 42ca387..7aa9bae 100644 --- a/src/main.lua +++ b/src/main.lua @@ -60,9 +60,10 @@ local ball = { x = Center.x, y = Center.y, size = 6, + heldBy = nil --[[@type Runner | nil]], } -local BatLength = 45 +local BatLength = 50 --45 local Modes = { batting = {}, @@ -146,7 +147,7 @@ function resetFielderPositions(fromOffTheField) fielders.catcher.target = xy(Screen.W * 0.475, Screen.H * 0.92) fielders.left.target = xy(Screen.W * -1, Screen.H * -0.2) fielders.center.target = xy(Center.x, Screen.H * -0.4) - fielders.right.target = xy(Screen.W * 2, Screen.H * fielders.left.target.y) + fielders.right.target = xy(Screen.W * 2, fielders.left.target.y) end local BatterStartingX = Bases[Home].x - 40 @@ -179,6 +180,7 @@ function throwBall(destX, destY, easingFunc, flyTimeMs, floaty) if not flyTimeMs then flyTimeMs = distanceBetween(ball.x, ball.y, destX, destY) * 5 end + ball.heldBy = nil ballSizeAnimator:reset(flyTimeMs) ballAnimatorY = gfx.animator.new(flyTimeMs, ball.y, destY, easingFunc) ballAnimatorX = gfx.animator.new(flyTimeMs, ball.x, destX, easingFunc) @@ -264,25 +266,24 @@ function updateFielders() fielder.x = fielder.x - (x * fielder.speed * deltaSeconds) fielder.y = fielder.y - (y * fielder.speed * deltaSeconds) else + fielder.target = nil if fielder.onArrive then fielder.onArrive() end - fielder.target = nil end end if currentMode == Modes.running and isTouchingBall(fielder.x, fielder.y) then local touchedBase = isTouchingBase(fielder.x, fielder.y) for i, runner in pairs(runners) do - local runnerOnBase = touchingBaseCache.get(runner) if touchedBase - and runner.prevBase + and runner.prevBase -- Check if the runner is standing at home and runner.forcedTo == touchedBase - and touchedBase ~= runnerOnBase + and touchedBase ~= touchingBaseCache.get(runner) then outRunner(i) - elseif not runnerOnBase then + elseif not touchingBaseCache.get(runner) then if distanceBetween(runner.x, runner.y, fielder.x, fielder.y) < TagDistance then outRunner(i) end @@ -468,10 +469,16 @@ function updateBatting() local chasingFielder = getNearestOf(fielders, ballDestX, ballDestY) chasingFielder.target = { x = ballDestX, y = ballDestY } chasingFielder.onArrive = function() + chasingFielder.onArrive = nil local targetX, targetY = getNextThrowTarget() - if targetX ~= nil then - throwBall(targetX, targetY, playdate.easingFunctions.linear, nil, true) - chasingFielder.onArrive = nil + if targetX ~= nil and targetY ~= nil then + local nearestFielder = getNearestOf(fielders, targetX, targetY) + nearestFielder.target = xy(targetX, targetY) + if nearestFielder == chasingFielder then + ball.heldBy = chasingFielder + else + throwBall(targetX, targetY, playdate.easingFunctions.linear, nil, true) + end end end end @@ -510,8 +517,13 @@ function updateGameState() elapsedSec = elapsedSec + deltaSeconds crankChange, acceleratedChange = playdate.getCrankChange() --[[@as number, number]] - ball.x = ballAnimatorX:currentValue() - ball.y = ballAnimatorY:currentValue() + ballFloatAnimator:currentValue() + if ball.heldBy then + ball.x = ball.heldBy.x + ball.y = ball.heldBy.y + else + ball.x = ballAnimatorX:currentValue() + ball.y = ballAnimatorY:currentValue() + ballFloatAnimator:currentValue() + end if currentMode == Modes.batting then updateBatting() diff --git a/src/utils.lua b/src/utils.lua index 49a2b43..749132e 100644 --- a/src/utils.lua +++ b/src/utils.lua @@ -3,12 +3,6 @@ import 'CoreLibs/animation.lua' import 'CoreLibs/graphics.lua' -- stylua: ignore end --- number = ((number * 2) - 1) --- return number * number - --- c = c + 0.0 -- convert to float to prevent integer overflow --- return c * t / d + b - function easingHill(t, b, c, d) c = c + 0.0 -- convert to float to prevent integer overflow t = t / d @@ -109,12 +103,22 @@ function getNearestOf(array, x, y, extraCondition) return nearest, nearestDistance end +--- Marker used by buildCache to indicate a cached `nil` value. local NoValue = {} +--- Build a simple fetcher cache. On calling `get()`, if no value has already +--- been fetched, calls `fetcher(key)`, then caches and returns that value. +--- +--- On reflection, it's probably pretty early for this optimization, and it's +--- optimizing in favor of CPU at the expense of memory, which is probably not +--- where the playdate's limitaitons lie. But it can stay for now. +--- +---@generic Key +---@generic Value +---@return { get: fun(key: Key): Value } function buildCache(fetcher) local cacheData = {} return { - cacheDate = cacheData, get = function(key) if cacheData[key] == NoValue then return nil @@ -122,7 +126,8 @@ function buildCache(fetcher) if cacheData[key] ~= nil then return cacheData[key] end - cacheData[key] = fetcher(key) or NoValue + local fetched = fetcher(key) + cacheData[key] = fetched ~= nil and fetched or NoValue return cacheData[key] end, }