Add swing-and-a-miss strikes

This commit is contained in:
Sage Vaillancourt 2025-02-17 20:37:16 -05:00
parent 4c9fbcdee7
commit e20ad0d3ad
3 changed files with 24 additions and 14 deletions

View File

@ -72,7 +72,8 @@ local teams <const> = {
---@field deltaSeconds number ---@field deltaSeconds number
---@field ball Ball ---@field ball Ball
---@field battingTeam TeamId ---@field battingTeam TeamId
---@field catcherThrownBall boolean ---@field pitchIsOver boolean
---@field didSwing boolean
---@field offenseState OffenseState ---@field offenseState OffenseState
---@field inning number ---@field inning number
---@field stats Statistics ---@field stats Statistics
@ -109,7 +110,7 @@ Game = {}
function Game.new(settings, announcer, fielding, baserunning, npc, state) function Game.new(settings, announcer, fielding, baserunning, npc, state)
announcer = announcer or Announcer.new() announcer = announcer or Announcer.new()
fielding = fielding or Fielding.new() fielding = fielding or Fielding.new()
settings.userTeam = nil -- "away" settings.userTeam = "away"
local homeTeamBlipper = blipper.new(100, settings.homeTeamSprites.smiling, settings.homeTeamSprites.lowHat) local homeTeamBlipper = blipper.new(100, settings.homeTeamSprites.smiling, settings.homeTeamSprites.lowHat)
local awayTeamBlipper = blipper.new(100, settings.awayTeamSprites.smiling, settings.awayTeamSprites.lowHat) local awayTeamBlipper = blipper.new(100, settings.awayTeamSprites.smiling, settings.awayTeamSprites.lowHat)
@ -132,7 +133,8 @@ function Game.new(settings, announcer, fielding, baserunning, npc, state)
battingTeam = battingTeam, battingTeam = battingTeam,
offenseState = C.Offense.batting, offenseState = C.Offense.batting,
inning = 1, inning = 1,
catcherThrownBall = false, pitchIsOver = false,
didSwing = false,
secondsSinceLastRunnerMove = 0, secondsSinceLastRunnerMove = 0,
secondsSincePitchAllowed = 0, secondsSincePitchAllowed = 0,
battingTeamSprites = settings.awayTeamSprites, battingTeamSprites = settings.awayTeamSprites,
@ -237,7 +239,7 @@ end
function Game:pitch(pitchFlyTimeMs, pitchTypeIndex) function Game:pitch(pitchFlyTimeMs, pitchTypeIndex)
Fielding.markIneligible(self.fielding.fielders.pitcher) Fielding.markIneligible(self.fielding.fielders.pitcher)
self.state.ball.heldBy = nil self.state.ball.heldBy = nil
self.state.catcherThrownBall = false self.state.pitchIsOver = false
self.state.offenseState = C.Offense.batting self.state.offenseState = C.Offense.batting
local current = Pitches[pitchTypeIndex](self.state.ball) local current = Pitches[pitchTypeIndex](self.state.ball)
@ -370,8 +372,14 @@ function Game:strikeOut()
self:nextBatter() self:nextBatter()
end end
local SwingBackDeg <const> = 30
local SwingForwardDeg <const> = 170
---@param batDeg number ---@param batDeg number
function Game:updateBatting(batDeg, batSpeed) function Game:updateBatting(batDeg, batSpeed)
if not self.state.pitchIsOver and batDeg > SwingBackDeg and batDeg < SwingForwardDeg then
self.state.didSwing = true
end
local batAngle = math.rad(batDeg) local batAngle = math.rad(batDeg)
-- TODO: animate bat-flip or something -- TODO: animate bat-flip or something
self.state.batBase.x = self.baserunning.batter and (self.baserunning.batter.x + C.BatterHandPos.x) or 0 self.state.batBase.x = self.baserunning.batter and (self.baserunning.batter.x + C.BatterHandPos.x) or 0
@ -480,8 +488,8 @@ function Game:updateGameState()
self.state.secondsSincePitchAllowed = self.state.secondsSincePitchAllowed + self.state.deltaSeconds self.state.secondsSincePitchAllowed = self.state.secondsSincePitchAllowed + self.state.deltaSeconds
end end
if self.state.secondsSincePitchAllowed > C.ReturnToPitcherAfterSeconds and not self.state.catcherThrownBall then if self.state.secondsSincePitchAllowed > C.ReturnToPitcherAfterSeconds and not self.state.pitchIsOver then
local outcome = pitchTracker:updatePitchCounts() local outcome = pitchTracker:updatePitchCounts(self.state.didSwing)
local currentPitchingStats = self:fieldingTeamCurrentInning().pitching local currentPitchingStats = self:fieldingTeamCurrentInning().pitching
if outcome == PitchOutcomes.Strike or outcome == PitchOutcomes.StrikeOut then if outcome == PitchOutcomes.Strike or outcome == PitchOutcomes.StrikeOut then
currentPitchingStats.strikes = currentPitchingStats.strikes + 1 currentPitchingStats.strikes = currentPitchingStats.strikes + 1
@ -496,7 +504,8 @@ function Game:updateGameState()
end end
-- Catcher has the ball. Throw it back to the pitcher -- Catcher has the ball. Throw it back to the pitcher
self.state.ball:launch(C.PitchStartX, C.PitchStartY, playdate.easingFunctions.linear, nil, true) self.state.ball:launch(C.PitchStartX, C.PitchStartY, playdate.easingFunctions.linear, nil, true)
self.state.catcherThrownBall = true self.state.pitchIsOver = true
self.state.didSwing = false
end end
local batSpeed local batSpeed
@ -505,7 +514,7 @@ function Game:updateGameState()
batSpeed = crankLimited batSpeed = crankLimited
else else
self.state.batAngleDeg = self.state.batAngleDeg =
self.npc:updateBatAngle(self.state.ball, self.state.catcherThrownBall, self.state.deltaSeconds) self.npc:updateBatAngle(self.state.ball, self.state.pitchIsOver, self.state.deltaSeconds)
batSpeed = self.npc:batSpeed() * self.state.deltaSeconds batSpeed = self.npc:batSpeed() * self.state.deltaSeconds
end end
@ -521,7 +530,7 @@ function Game:updateGameState()
self:userPitch(throwFly) self:userPitch(throwFly)
end end
else else
self:pitch(C.PitchFlyMs / self.npc:pitchSpeed(), math.random(#Pitches)) self:pitch(C.PitchFlyMs / self.npc:pitchSpeed(), 2)
end end
end end
elseif self.state.offenseState == C.Offense.running then elseif self.state.offenseState == C.Offense.running then

View File

@ -19,12 +19,12 @@ function Npc.new(runners, fielders)
end end
---@param ball XyPair ---@param ball XyPair
---@param catcherThrownBall boolean ---@param pitchIsOver boolean
---@param deltaSec number ---@param deltaSec number
---@return number ---@return number
-- luacheck: no unused -- luacheck: no unused
function Npc:updateBatAngle(ball, catcherThrownBall, deltaSec) function Npc:updateBatAngle(ball, pitchIsOver, deltaSec)
if not catcherThrownBall and ball.y > 200 and ball.y < 230 and (ball.x < C.Center.x + 15) then if not pitchIsOver and ball.y > 200 and ball.y < 230 and (ball.x < C.Center.x + 15) then
npcBatDeg = npcBatDeg + (deltaSec * npcBatSpeed) npcBatDeg = npcBatDeg + (deltaSec * npcBatSpeed)
else else
npcBatSpeed = (1 + math.random()) * BaseNpcBatSpeed npcBatSpeed = (1 + math.random()) * BaseNpcBatSpeed

View File

@ -265,12 +265,13 @@ pitchTracker = {
self.balls = 0 self.balls = 0
end, end,
updatePitchCounts = function(self) ---@param didSwing boolean
updatePitchCounts = function(self, didSwing)
if not self.recordedPitchX then if not self.recordedPitchX then
return return
end end
if self.recordedPitchX > C.StrikeZoneStartX and self.recordedPitchX < C.StrikeZoneEndX then if didSwing or self.recordedPitchX > C.StrikeZoneStartX and self.recordedPitchX < C.StrikeZoneEndX then
self.strikes = self.strikes + 1 self.strikes = self.strikes + 1
if self.strikes >= 3 then if self.strikes >= 3 then
self:reset() self:reset()