diff --git a/Makefile b/Makefile index a8cba8b..09674bf 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -SOURCE_FILES := src/utils.lua src/graphics.lua src/main.lua +SOURCE_FILES := src/utils.lua src/graphics.lua src/scoreboard.lua src/main.lua all: pdc src BatterUp.pdx diff --git a/__stub.ext.lua b/__stub.ext.lua index da90630..1f41e90 100644 --- a/__stub.ext.lua +++ b/__stub.ext.lua @@ -13,3 +13,7 @@ json = json -- selene: allow(unused_variable) -- selene: allow(unscoped_variables) kTextAlignment = kTextAlignment + +-- selene: allow(unused_variable) +-- selene: allow(unscoped_variables) +printTable = printTable \ No newline at end of file diff --git a/src/main.lua b/src/main.lua index 1040a06..dbdf366 100644 --- a/src/main.lua +++ b/src/main.lua @@ -7,18 +7,16 @@ import 'CoreLibs/object.lua' import 'CoreLibs/timer.lua' import 'CoreLibs/ui.lua' +--- @alias XYPair { x: number, y: number } +--- @alias Base { x: number, y: number } +--- @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 } + import 'graphics.lua' +import 'scoreboard.lua' import 'utils.lua' -- stylua: ignore end ---- @alias XYPair { x: number, y: number } - ---- @alias Base { x: number, y: number } - ---- @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 } - local gfx = playdate.graphics local Screen = { @@ -32,8 +30,6 @@ local BatCrackSound = playdate.sound.sampleplayer.new("sounds/bat-crack- local GrassBackground = gfx.image.new("images/game/grass.png") --[[@as pd_image]] local PlayerFrown = gfx.image.new("images/game/player-frown.png") --[[@as pd_image]] -local ScoreFont = gfx.font.new("fonts/font-full-circle.pft") - local PlayerImageBlipper = blipper.new(100, "images/game/player.png", "images/game/player-lowhat.png") local DanceBounceMs = 500 @@ -234,26 +230,38 @@ function isTouchingBall(x, y) return ballDistance < BallCatchHitbox end -local outs = 0 -local homeScore = 0 -local awayScore = 0 +local teams = { + home = { + score = 0, + }, + away = { + score = 0, + }, +} +local battingTeam = teams.away +local outs = 0 function updateForcedRunners() end function outRunner(runnerIndex) - outs = math.min(3, outs + 1) + outs = outs + 1 outRunners[#outRunners + 1] = runners[runnerIndex] table.remove(runners, runnerIndex) FielderDanceAnimator:reset() updateForcedRunners() announcer:say("YOU'RE OUT!") + if outs == 3 then + outs = 0 + announcer:say("SWITCHING SIDES...") + battingTeam = battingTeam == teams.home and teams.away or teams.home + end end -- TODO: Away score function score(runnerIndex) outRunners[#outRunners + 1] = runners[runnerIndex] table.remove(runners, runnerIndex) - homeScore = homeScore + 1 + battingTeam.score = battingTeam.score + 1 announcer:say("SCORE!") end @@ -542,46 +550,12 @@ function updateGameState() updateOutRunners() end -local OUT_BUBBLE_SIZE = 5 - -function drawScoreboard() - gfx.setFont(ScoreFont) - gfx.setDrawOffset(0, 0) - local y = Screen.H * 0.97 - local x = 15 - - gfx.setLineWidth(1) - gfx.setColor(gfx.kColorBlack) - gfx.fillRect(x - 15, y - 44, 75, 55) - - gfx.setColor(gfx.kColorWhite) - for i = outs, 2 do - gfx.drawCircleAtPoint(x - 2 + (i * 2.5 * OUT_BUBBLE_SIZE), y, OUT_BUBBLE_SIZE) - end - for i = 0, (outs - 1) do - gfx.fillCircleAtPoint(x - 2 + (i * 2.5 * OUT_BUBBLE_SIZE), y, OUT_BUBBLE_SIZE) - end - - local originalDrawMode = gfx.getImageDrawMode() - gfx.setImageDrawMode(playdate.graphics.kDrawModeInverted) - 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 - function playdate.update() - updateGameState() - playdate.graphics.animation.blinker.updateAll() playdate.timer.updateTimers() + updateGameState() + gfx.animation.blinker.updateAll() + gfx.clear() if ball.x < BallOffscreen then @@ -620,7 +594,8 @@ function playdate.update() PlayerFrown:draw(runner.x, runner.y) end - drawScoreboard() + gfx.setDrawOffset(0, 0) + drawScoreboard(0, Screen.H * 0.77, teams, outs) announcer:draw(Center.x, 10) end diff --git a/src/scoreboard.lua b/src/scoreboard.lua new file mode 100644 index 0000000..db4eb2b --- /dev/null +++ b/src/scoreboard.lua @@ -0,0 +1,41 @@ +local ScoreFont = playdate.graphics.font.new("fonts/font-full-circle.pft") +local OutBubbleRadius = 5 +local ScoreboardMarginX = 8 +local ScoreboardHeight = 55 + +function drawScoreboard(x, y, teams, outs) + local gfx = playdate.graphics + + local homeScore = teams.home.score + local awayScore = teams.away.score + + local homeScoreText = "HOME " .. (homeScore > 9 and homeScore or " " .. homeScore) + local awayScoreText = "AWAY " .. (awayScore > 9 and awayScore or " " .. awayScore) + + local rectWidth = (ScoreboardMarginX * 2) + ScoreFont:getTextWidth(homeScoreText) + + gfx.setLineWidth(1) + gfx.setColor(gfx.kColorBlack) + gfx.fillRect(x, y, rectWidth, ScoreboardHeight) + + local originalDrawMode = gfx.getImageDrawMode() + gfx.setImageDrawMode(gfx.kDrawModeInverted) + + ScoreFont:drawText(homeScoreText, x + ScoreboardMarginX, y + 6) + ScoreFont:drawText(awayScoreText, x + ScoreboardMarginX, y + 22) + + gfx.setImageDrawMode(originalDrawMode) + + gfx.setColor(gfx.kColorWhite) + + function circleParams(i) + return (x + ScoreboardMarginX + OutBubbleRadius) + (i * 2.5 * OutBubbleRadius), y + 46, OutBubbleRadius + end + + for i = outs, 2 do + gfx.drawCircleAtPoint(circleParams(i)) + end + for i = 0, (outs - 1) do + gfx.fillCircleAtPoint(circleParams(i)) + end +end diff --git a/src/utils.lua b/src/utils.lua index 6476029..d21b833 100644 --- a/src/utils.lua +++ b/src/utils.lua @@ -136,19 +136,24 @@ end local AnnouncementFont = playdate.graphics.font.new("fonts/Roobert-20-Medium.pft") -- selene: allow(unscoped_variables) -announcer = {} +announcer = { + textQueue = {}, +} function announcer.say(self, text, durationMs) - self.text = text - durationMs = durationMs and durationMs or 3000 + self.textQueue[#self.textQueue + 1] = text + -- Could cause some timing funk if messages are queued up asyncronously. + -- I.e. `:say("hello")` <1.5 seconds pass> `:say("hello")` would result + -- in the second message being displayed for 4.5 seconds instead of just 3. + durationMs = durationMs and durationMs or (3000 * #self.textQueue) playdate.timer.new(durationMs, function() - self.text = nil + table.remove(self.textQueue, 1) end) end function announcer.draw(self, x, y) - if not self.text then + if #self.textQueue == 0 then return end - AnnouncementFont:drawTextAligned(self.text, x, y, kTextAlignment.center) + AnnouncementFont:drawTextAligned(self.textQueue[1], x, y, kTextAlignment.center) end