Multiple pitches. Track innings.

Have catcher throw ball back to pitcher.
NOTE: Bit of a timer hack in init() to get the ball to the pitcher at the beginning of the game.
This commit is contained in:
Sage Vaillancourt 2025-02-03 18:57:45 -05:00
parent 14629a5346
commit 5d01769eb1
2 changed files with 61 additions and 16 deletions

View File

@ -64,11 +64,20 @@ end
local BallOffscreen <const> = 999 local BallOffscreen <const> = 999
local PitchFlyMs <const> = 2500 local PitchFlyMs <const> = 1000
local PitchStartX <const> = 200 local PitchStartX <const> = 200
local PitchStartY <const>, PitchEndY <const> = 90, 250 local PitchStartY <const>, PitchEndY <const> = 90, 240
local PitchAnimator <const> = gfx.animator.new(PitchFlyMs, PitchStartY, PitchEndY, playdate.easingFunctions.outQuint) local PitchesX <const> = {
-- Fastball
gfx.animator.new(0, PitchStartX, PitchStartX, playdate.easingFunctions.linear),
-- Slider
gfx.animator.new(PitchFlyMs, PitchStartX - 20, PitchStartX, easingHill),
-- Curve ball
gfx.animator.new(PitchFlyMs, PitchStartX + 20, PitchStartX, easingHill),
}
local PitchAnimatorY <const> = gfx.animator.new(PitchFlyMs, PitchStartY, PitchEndY, playdate.easingFunctions.linear)
local CrankOffsetDeg <const> = 90 local CrankOffsetDeg <const> = 90
local BatOffset <const> = xy(10, 25) local BatOffset <const> = xy(10, 25)
@ -211,15 +220,21 @@ function throwBall(destX, destY, easingFunc, flyTimeMs, floaty)
end end
end end
local PitchAfterSeconds = 5 local PitchAfterSeconds = 7
-- TODO: Replace with a timer, repeatedly reset instead of setting to 0 -- TODO: Replace with a timer, repeatedly reset instead of setting to 0
local secondsSincePitchAllowed = -5 local secondsSincePitchAllowed = -5
local catcherThrownBall = false
function pitch() function pitch()
catcherThrownBall = false
currentMode = Modes.batting currentMode = Modes.batting
ballAnimatorX = gfx.animator.new(0, PitchStartX, PitchStartX, playdate.easingFunctions.linear) ballAnimatorX = PitchesX[math.random(#PitchesX)]
ballAnimatorY = PitchAnimator ballAnimatorY = PitchAnimatorY
PitchAnimator:reset()
ballAnimatorX:reset()
ballAnimatorY:reset()
secondsSincePitchAllowed = 0 secondsSincePitchAllowed = 0
end end
@ -256,6 +271,7 @@ local teams <const> = {
local battingTeam = teams.away local battingTeam = teams.away
local outs = 0 local outs = 0
local inning = 1
---@param base Base ---@param base Base
---@return Runner | nil ---@return Runner | nil
@ -293,12 +309,26 @@ function outRunner(runnerIndex)
updateForcedRunners() updateForcedRunners()
announcer:say("YOU'RE OUT!") announcer:say("YOU'RE OUT!")
if outs == 3 then if outs == 3 then
outs = 0 local gameOver = inning == 9 and teams.away.score ~= teams.home.score
if not gameOver then
announcer:say("SWITCHING SIDES...") announcer:say("SWITCHING SIDES...")
end
while #runners > 0 do while #runners > 0 do
outRunners[#outRunners + 1] = table.remove(runners, #runners) outRunners[#outRunners + 1] = table.remove(runners, #runners)
end end
battingTeam = battingTeam == teams.home and teams.away or teams.home -- Delay to keep end-of-inning on the scoreboard for a few seconds
playdate.timer.new(3000, function()
outs = 0
if battingTeam == teams.home then
battingTeam = teams.away
inning = inning + 1
else
battingTeam = teams.home
end
if gameOver then
announcer:say("AND THAT'S THE BALL GAME!")
end
end)
end end
end end
@ -333,11 +363,12 @@ function updateFielders()
end end
if currentMode == Modes.running and isTouchingBall(fielder.x, fielder.y) then if currentMode == Modes.running and isTouchingBall(fielder.x, fielder.y) then
-- TODO: Check for double-plays or other available outs.
local touchedBase = isTouchingBase(fielder.x, fielder.y) local touchedBase = isTouchingBase(fielder.x, fielder.y)
for i, runner in pairs(runners) do for i, runner in pairs(runners) do
if if
touchedBase touchedBase
and runner.prevBase -- Check if the runner is standing at home and runner.prevBase -- Make sure the runner is not standing at home
and runner.forcedTo == touchedBase and runner.forcedTo == touchedBase
and touchedBase ~= touchingBaseCache.get(runner) and touchedBase ~= touchingBaseCache.get(runner)
then then
@ -454,7 +485,7 @@ function getNextThrowTarget()
end end
end end
local ResetFieldersAfterSeconds = 4 local ResetFieldersAfterSeconds = 2
-- TODO: Replace with a timer, repeatedly reset instead of setting to 0 -- TODO: Replace with a timer, repeatedly reset instead of setting to 0
local secondsSinceLastRunnerMove = 0 local secondsSinceLastRunnerMove = 0
@ -464,6 +495,10 @@ function init()
playdate.setMenuImage(gfx.image.new("images/game/menu-image.png")) playdate.setMenuImage(gfx.image.new("images/game/menu-image.png"))
resetFielderPositions(true) resetFielderPositions(true)
playdate.getSystemMenu():addMenuItem("Restart game", function() end) playdate.getSystemMenu():addMenuItem("Restart game", function() end)
playdate.timer.new(2000, function()
throwBall(PitchStartX, PitchStartY, playdate.easingFunctions.linear, nil, false)
end)
end end
function tryToThrowOut(self) function tryToThrowOut(self)
@ -527,7 +562,7 @@ function updateBatting()
end end
function updateRunning() function updateRunning()
local nonBatterRunners = filter(runners, function (runner) local nonBatterRunners = filter(runners, function(runner)
return runner ~= batter return runner ~= batter
end) end)
ball.size = ballSizeAnimator:currentValue() ball.size = ballSizeAnimator:currentValue()
@ -571,6 +606,10 @@ function updateGameState()
if currentMode == Modes.batting then if currentMode == Modes.batting then
secondsSincePitchAllowed = secondsSincePitchAllowed + deltaSeconds secondsSincePitchAllowed = secondsSincePitchAllowed + deltaSeconds
if secondsSincePitchAllowed > 3.5 and not catcherThrownBall then
throwBall(PitchStartX, PitchStartY, playdate.easingFunctions.linear, nil, true)
catcherThrownBall = true
end
if secondsSincePitchAllowed > PitchAfterSeconds then if secondsSincePitchAllowed > PitchAfterSeconds then
pitch() pitch()
end end
@ -629,7 +668,7 @@ function playdate.update()
end end
gfx.setDrawOffset(0, 0) gfx.setDrawOffset(0, 0)
drawScoreboard(0, Screen.H * 0.77, teams, outs, battingTeam) drawScoreboard(0, Screen.H * 0.77, teams, outs, battingTeam, inning)
announcer:draw(Center.x, 10) announcer:draw(Center.x, 10)
end end

View File

@ -1,6 +1,7 @@
local ScoreFont <const> = playdate.graphics.font.new("fonts/font-full-circle.pft") local ScoreFont <const> = playdate.graphics.font.new("fonts/font-full-circle.pft")
local OutBubbleRadius <const> = 5 local OutBubbleRadius <const> = 5
local ScoreboardMarginX <const> = 6 local ScoreboardMarginX <const> = 6
local ScoreboardMarginRight <const> = 4
local ScoreboardHeight <const> = 55 local ScoreboardHeight <const> = 55
local Indicator = "> " local Indicator = "> "
local IndicatorWidth <const> = ScoreFont:getTextWidth(Indicator) local IndicatorWidth <const> = ScoreFont:getTextWidth(Indicator)
@ -15,7 +16,7 @@ function getIndicators(teams, battingTeam)
return "", IndicatorWidth, Indicator, 0 return "", IndicatorWidth, Indicator, 0
end end
function drawScoreboard(x, y, teams, outs, battingTeam) function drawScoreboard(x, y, teams, outs, battingTeam, inning)
local gfx = playdate.graphics local gfx = playdate.graphics
local homeScore = teams.home.score local homeScore = teams.home.score
@ -26,7 +27,10 @@ function drawScoreboard(x, y, teams, outs, battingTeam)
local homeScoreText = homeIndicator .. "HOME " .. (homeScore > 9 and homeScore or " " .. homeScore) local homeScoreText = homeIndicator .. "HOME " .. (homeScore > 9 and homeScore or " " .. homeScore)
local awayScoreText = awayIndicator .. "AWAY " .. (awayScore > 9 and awayScore or " " .. awayScore) local awayScoreText = awayIndicator .. "AWAY " .. (awayScore > 9 and awayScore or " " .. awayScore)
local rectWidth = (ScoreboardMarginX * 2) + ScoreFont:getTextWidth(homeScoreText) + homeOffset local rectWidth = (ScoreboardMarginX * 2)
+ ScoreboardMarginRight
+ ScoreFont:getTextWidth(homeScoreText)
+ homeOffset
gfx.setLineWidth(1) gfx.setLineWidth(1)
gfx.setColor(gfx.kColorBlack) gfx.setColor(gfx.kColorBlack)
@ -37,6 +41,8 @@ function drawScoreboard(x, y, teams, outs, battingTeam)
ScoreFont:drawText(homeScoreText, x + ScoreboardMarginX + homeOffset, y + 6) ScoreFont:drawText(homeScoreText, x + ScoreboardMarginX + homeOffset, y + 6)
ScoreFont:drawText(awayScoreText, x + ScoreboardMarginX + awayOffset, y + 22) ScoreFont:drawText(awayScoreText, x + ScoreboardMarginX + awayOffset, y + 22)
local inningOffsetX = (x + ScoreboardMarginX + IndicatorWidth) + (4 * 2.5 * OutBubbleRadius)
ScoreFont:drawText(inning, inningOffsetX, y + 39)
gfx.setImageDrawMode(originalDrawMode) gfx.setImageDrawMode(originalDrawMode)