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 0000000..0176122 Binary files /dev/null and b/src/fonts/Full Circle/font-full-circle-table-12-15.png differ 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, }