Pitcher can throw to bases.

Logic should be re-usable generally for throwing between fielders.
This commit is contained in:
Sage Vaillancourt 2025-02-05 23:42:17 -05:00
parent 57625a9b80
commit 8319b554ec
2 changed files with 81 additions and 40 deletions

View File

@ -94,16 +94,16 @@ local Pitches <const> = {
x = gfx.animator.new(0, PitchStartX, PitchStartX, playdate.easingFunctions.linear),
y = gfx.animator.new(PitchFlyMs / 1.3, PitchStartY, PitchEndY, playdate.easingFunctions.linear),
},
-- Slider
{
x = gfx.animator.new(PitchFlyMs, PitchStartX - 20, PitchStartX, utils.easingHill),
y = gfx.animator.new(PitchFlyMs, PitchStartY, PitchEndY, playdate.easingFunctions.linear),
},
-- Curve ball
{
x = gfx.animator.new(PitchFlyMs, PitchStartX + 20, PitchStartX, utils.easingHill),
y = gfx.animator.new(PitchFlyMs, PitchStartY, PitchEndY, playdate.easingFunctions.linear),
},
-- Slider
{
x = gfx.animator.new(PitchFlyMs, PitchStartX - 20, PitchStartX, utils.easingHill),
y = gfx.animator.new(PitchFlyMs, PitchStartY, PitchEndY, playdate.easingFunctions.linear),
},
-- Wobbbleball
{
x = {
@ -322,11 +322,12 @@ local secondsSincePitchAllowed = -5
local catcherThrownBall = false
---@param pitchFlyTimeMs number | nil
function pitch(pitchFlyTimeMs)
---@param pitchTypeIndex number | nil
function pitch(pitchFlyTimeMs, pitchTypeIndex)
catcherThrownBall = false
offenseMode = Offense.batting
local current = Pitches[math.random(#Pitches)]
local current = Pitches[pitchTypeIndex or math.random(#Pitches)]
ballAnimatorX = current.x
ballAnimatorY = current.y or Pitches[1].y
@ -467,12 +468,14 @@ end
function getBaseOfStrandedRunner()
local farRunnersBase, farDistance
for _, runner in pairs(runners) do
if runner ~= batter then
local nearestBase, distance = utils.getNearestOf(Bases, runner.x, runner.y)
if farRunnersBase == nil or farDistance < distance then
farRunnersBase = nearestBase
farDistance = distance
end
end
end
return farRunnersBase, farDistance
end
@ -721,10 +724,10 @@ function walkAwayOutRunners()
end
local npcBatDeg = 0
local NpcBatSpeed <const> = 1200
local NpcBatSpeed <const> = 1500
function npcBatAngle()
if not catcherThrownBall and ball.y > 190 and ball.y < 230 and (ball.x < Center.x + 15) then
if not catcherThrownBall and ball.y > 200 and ball.y < 230 and (ball.x < Center.x + 15) then
npcBatDeg = npcBatDeg + (deltaSeconds * NpcBatSpeed)
else
npcBatDeg = 200
@ -742,21 +745,51 @@ function npcRunningSpeed()
end
local touchedBase = isTouchingBase(runners[1].x, runners[1].y)
if not touchedBase or touchedBase == Bases[Home] then
return 35
return 25
end
return 0
end
local pitchMeter = 0
local throwMeter = 0
local PitchMeterLimit = 25
function readPitch()
if pitchMeter > PitchMeterLimit then
return (PitchFlyMs / (pitchMeter / PitchMeterLimit))
function readThrow()
if throwMeter > PitchMeterLimit then
return (PitchFlyMs / (throwMeter / PitchMeterLimit))
end
return nil
end
---@param thrower Fielder
---@param throwFlyMs number
---@return boolean didThrow
function buttonControlledThrow(thrower, throwFlyMs, forbidThrowHome)
local targetBase
if playdate.buttonIsPressed(playdate.kButtonLeft) then
throwBall(Bases[Third].x, Bases[Third].y, playdate.easingFunctions.linear, throwFlyMs)
targetBase = Bases[Third]
elseif playdate.buttonIsPressed(playdate.kButtonUp) then
throwBall(Bases[Second].x, Bases[Second].y, playdate.easingFunctions.linear, throwFlyMs)
targetBase = Bases[Second] -- TODO - or shortstop - whoever's closer
elseif playdate.buttonIsPressed(playdate.kButtonRight) then
throwBall(Bases[First].x, Bases[First].y, playdate.easingFunctions.linear, throwFlyMs)
targetBase = Bases[First]
elseif not forbidThrowHome and playdate.buttonIsPressed(playdate.kButtonDown) then
throwBall(Bases[Home].x, Bases[Home].y, playdate.easingFunctions.linear, throwFlyMs)
targetBase = Bases[Home]
else
return false
end
local closestFielder = utils.getNearestOf(fielders, targetBase.x, targetBase.y, function(fielder)
return fielder ~= thrower
end)
closestFielder.target = targetBase
secondsSinceLastRunnerMove = 0
offenseMode = Offense.running
return true
end
function updateGameState()
deltaSeconds = playdate.getElapsedTime() or 0
playdate.resetElapsedTime()
@ -778,24 +811,31 @@ function updateGameState()
throwBall(PitchStartX, PitchStartY, playdate.easingFunctions.linear, nil, true)
catcherThrownBall = true
else
pitchMeter = 0
throwMeter = 0
end
if not playerOnOffense then
pitchMeter = math.max(0, pitchMeter - (deltaSeconds * 150))
pitchMeter = pitchMeter + crankChange
if pitchMeter > PitchMeterLimit then
printTable({ pitchMeter = pitchMeter })
end
throwMeter = math.max(0, throwMeter - (deltaSeconds * 150))
throwMeter = throwMeter + crankChange
end
if secondsSincePitchAllowed > PitchAfterSeconds then
if playerOnOffense then
pitch(PitchFlyMs)
else
local pitchFly = readPitch()
if pitchFly then
pitch(pitchFly)
local throwFly = readThrow()
if throwFly and not buttonControlledThrow(fielders.pitcher, throwFly, true) then
local aButton = playdate.buttonIsPressed(playdate.kButtonA)
local bButton = playdate.buttonIsPressed(playdate.kButtonB)
if not aButton and not bButton then
pitch(throwFly, 1)
elseif aButton and not bButton then
pitch(throwFly, 2)
elseif not aButton and bButton then
pitch(throwFly, 3)
elseif aButton and bButton then
pitch(throwFly, 4)
end
end
end
end
@ -814,10 +854,12 @@ function updateGameState()
throwBall(PitchStartX, PitchStartY, playdate.easingFunctions.linear, nil, true)
resetFielderPositions()
offenseMode = Offense.batting
if not batter then
batter = newRunner()
end
end
end
end
updateFielders()
walkAwayOutRunners()
@ -829,11 +871,10 @@ function drawMinimap() end
---@param fielder Fielder
---@return boolean isHoldingBall
function drawFielderGlove(fielder)
printTable({ ballFloatValue = ballFloatAnimator:currentValue() })
local distanceFromBall =
utils.distanceBetweenZ(fielder.x, fielder.y, 0, ball.x, ball.y, ballFloatAnimator:currentValue())
local shoulderX, shoulderY = fielder.x + 10, fielder.y + FielderDanceAnimator:currentValue() + 5
if distanceFromBall > 30 then
if distanceFromBall > 20 then
Glove:draw(shoulderX, shoulderY)
return false
else

View File

@ -43,8 +43,8 @@ end
---@param y2 number
---@return number x, number y, number distance
function utils.normalizeVector(x1, y1, x2, y2)
local distance, a, b = utils.distanceBetween(x1, y1, x2, y2)
return a / distance, b / distance, distance
local distance, x, y = utils.distanceBetween(x1, y1, x2, y2)
return x / distance, y / distance, distance
end
---@generic T
@ -63,17 +63,17 @@ end
---@return number distance, number x, number y
function utils.distanceBetween(x1, y1, x2, y2)
local a = x1 - x2
local b = y1 - y2
return math.sqrt((a * a) + (b * b)), a, b
local x = x1 - x2
local y = y1 - y2
return math.sqrt((x * x) + (y * y)), x, y
end
---@return number distance, number x, number y
---@return number distance, number x, number y, number z
function utils.distanceBetweenZ(x1, y1, z1, x2, y2, z2)
local a = x1 - x2
local b = y1 - y2
local c = z1 - z2
return math.sqrt((a * a) + (b * b) + (c * c)), a, b
local x = x1 - x2
local y = y1 - y2
local z = z1 - z2
return math.sqrt((x * x) + (y * y) + (z * z)), x, y, z
end
--- Returns true only if the point is below the given line, within the x bounds of said line, and above the bottomBound