diff --git a/Makefile b/Makefile index 72976b1..6433974 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,8 @@ all: pdc src BatterUp.pdx check: + stylua -c src/ cat __stub.ext.lua <(sed 's/^function/-- selene: allow(unused_variable)\nfunction/' ${PLAYDATE_SDK_PATH}/CoreLibs/__stub.lua) ${SOURCE_FILES} | grep -v '^import' | sed 's///g' | selene - -lint: check +lint: stylua src/ diff --git a/src/fonts/Full Circle/font-full-circle.fnt b/src/fonts/Full Circle/font-full-circle.fnt new file mode 100644 index 0000000..a180974 --- /dev/null +++ b/src/fonts/Full Circle/font-full-circle.fnt @@ -0,0 +1,96 @@ +space 4 +! 3 +" 8 +# 8 +$ 9 +% 9 +& 11 +' 4 +( 6 +) 6 +* 9 ++ 7 +, 4 +- 8 +. 4 +/ 7 +0 9 +1 6 +2 9 +3 9 +4 9 +5 9 +6 9 +7 9 +8 9 +9 9 +: 4 +; 4 +< 7 += 8 +> 7 +? 8 +@ 13 +A 9 +B 9 +C 9 +D 9 +E 9 +F 9 +G 9 +H 9 +I 3 +J 7 +K 9 +L 8 +M 11 +N 11 +O 9 +P 9 +Q 9 +R 9 +S 9 +T 9 +U 9 +V 9 +W 11 +X 9 +Y 9 +Z 9 +[ 6 +\ 7 +] 6 +^ 10 +_ 9 +` 4 +a 9 +b 9 +c 9 +d 9 +e 9 +f 7 +g 9 +h 9 +i 3 +j 7 +k 9 +l 6 +m 13 +n 9 +o 9 +p 9 +q 9 +r 7 +s 9 +t 8 +u 9 +v 9 +w 10 +x 9 +y 9 +z 9 +{ 6 +| 3 +} 6 +~ 8 +… 12 diff --git a/src/main.lua b/src/main.lua index 3b113d9..42ca387 100644 --- a/src/main.lua +++ b/src/main.lua @@ -14,7 +14,7 @@ import 'utils.lua' --- @alias Base { x: number, y: number } ---- @alias Runner { x: number, y: number, nextBase: Base, prevBase: Base, forcedTo: Base } +--- @alias Runner { x: number, y: number, nextBase: Base, prevBase: Base | nil, forcedTo: Base } --- @alias Fielder { onArrive: fun() | nil, x: number | nil, y: number | nil, target: XYPair | nil, speed: number } @@ -31,6 +31,8 @@ local BatCrackSound = playdate.sound.sampleplayer.new("sounds/bat-crack- local GrassBackground = gfx.image.new("images/game/grass.png") --[[@as PlaydateGraphicsImage]] local PlayerFrown = gfx.image.new("images/game/player-frown.png") --[[@as PlaydateGraphicsImage]] +local ScoreFont = gfx.font.new("fonts/Full Circle/font-full-circle.pft") + local PlayerImageBlipper = blipper.new(100, "images/game/player.png", "images/game/player-lowhat.png") local DanceBounceMs = 500 @@ -78,7 +80,7 @@ local ballFloatAnimator = gfx.animator.new(2000, -60, 0, easingHill) local BallSizeMs = 2000 local ballSizeAnimator = gfx.animator.new(BallSizeMs, 9, 6, easingHill) -local HitMult = 10 +local HitMult = 20 local deltaSeconds = 0 @@ -293,8 +295,9 @@ end --- Returns true if at least one runner is still moving ---@return boolean function updateRunners() - local autoRunSpeed = 20 + local autoRunSpeed = 20 * deltaSeconds --autoRunSpeed = 140 + -- TODO: Filter for the runner closest to the currently-held direction button local currentRunners = currentMode == Modes.batting and { batter } or filter(runners, function(runner) return runner ~= batter @@ -302,7 +305,9 @@ function updateRunners() local runnerMoved = false for runnerIndex, runner in ipairs(currentRunners) do + local appliedSpeed = crankChange -- TODO: Allow for individual runner control via buttons local nearestBase, nearestBaseDistance = getNearestOf(Bases, runner.x, runner.y) + if nearestBaseDistance < 5 and runner.prevBase @@ -311,21 +316,31 @@ function updateRunners() then score(runnerIndex) end + 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 local prevX, prevY = runner.x, runner.y - -- TODO: Drift toward nearest base? - local autoRun = nearestBaseDistance > 5 and mult * autoRunSpeed * deltaSeconds or 0 - mult = autoRun + (crankChange / 20) + local mult = 1 + if appliedSpeed < 0 then + if runner.prevBase then + mult = -1 + else + -- Don't allow running backwards when approaching the plate + appliedSpeed = 0 + end + end + + -- TODO: Also move if forced to 😅 + local autoRun = nearestBaseDistance > 40 and mult * autoRunSpeed + or nearestBaseDistance < 5 and 0 + or (nearestBase == runner.nextBase and autoRunSpeed or -1 * autoRunSpeed) + mult = autoRun + (appliedSpeed / 20) runner.x = runner.x - (x * mult) runner.y = runner.y - (y * mult) + runnerMoved = runnerMoved or prevX ~= runner.x or prevY ~= runner.y else runner.nextBase = NextBaseMap[runner.nextBase] @@ -509,29 +524,38 @@ function updateGameState() updateOutRunners() end -local OUT_BUBBLE_SIZE = 6 +local OUT_BUBBLE_SIZE = 5 function drawScoreboard() + gfx.setFont(ScoreFont) gfx.setDrawOffset(0, 0) - local y = Screen.H * 0.95 - local x = Screen.W * 0.05 + local y = Screen.H * 0.97 + local x = 15 gfx.setLineWidth(1) gfx.setColor(gfx.kColorBlack) - gfx.fillRect(x - 15, y - 44, 73, 55) + gfx.fillRect(x - 15, y - 44, 75, 55) gfx.setColor(gfx.kColorWhite) for i = outs, 2 do - gfx.drawCircleAtPoint(x + (i * 2.5 * OUT_BUBBLE_SIZE), y, OUT_BUBBLE_SIZE) + gfx.drawCircleAtPoint(x - 2 + (i * 2.5 * OUT_BUBBLE_SIZE), y, OUT_BUBBLE_SIZE) end for i = 0, (outs - 1) do - gfx.fillCircleAtPoint(x + (i * 2.5 * OUT_BUBBLE_SIZE), y, OUT_BUBBLE_SIZE) + gfx.fillCircleAtPoint(x - 2 + (i * 2.5 * OUT_BUBBLE_SIZE), y, OUT_BUBBLE_SIZE) end local originalDrawMode = gfx.getImageDrawMode() gfx.setImageDrawMode(playdate.graphics.kDrawModeInverted) - gfx.drawText("Home: " .. homeScore, x - 7, y - 40, 100, 20) - gfx.drawText("Away: " .. awayScore, x - 7, y - 25, 100, 20) + local numOffsetX = gfx.getTextSize("AWAY ") + + gfx.drawText("HOME ", x - 7, y - 38) + local homeScoreText = homeScore > 9 and homeScore or " " .. homeScore + gfx.drawText(homeScoreText, x - 7 + numOffsetX, y - 38) + + gfx.drawText("AWAY ", x - 7, y - 22) + local awayScoreText = awayScore > 9 and awayScore or " " .. awayScore + gfx.drawText(awayScoreText, x - 7 + numOffsetX, y - 22) + gfx.setImageDrawMode(originalDrawMode) end diff --git a/src/utils.lua b/src/utils.lua index 45f7f21..49a2b43 100644 --- a/src/utils.lua +++ b/src/utils.lua @@ -17,6 +17,13 @@ function easingHill(t, b, c, d) return (c * t) + b end +-- Useful for quick print-the-value-in-place debugging. +-- selene: allow(unused_variable) +function label(value, name) + print(name .. ": " .. value) + return value +end + ---@param x number ---@param y number ---@return XYPair