Remove Fielder.onArrive() callback

Instead, just try to throw for an out when touching the ball.
This also tentatively moves toward implementing cutoff throws.
Re-org to define tryToThrowOut() before it is referenced.
This commit is contained in:
Sage Vaillancourt 2025-02-04 13:04:26 -05:00
parent 1d55c27fa2
commit 44ba30ee97
1 changed files with 82 additions and 86 deletions

View File

@ -26,7 +26,6 @@ import 'CoreLibs/ui.lua'
--- } --- }
--- @alias Fielder { --- @alias Fielder {
--- onArrive: fun() | nil,
--- x: number | nil, --- x: number | nil,
--- y: number | nil, --- y: number | nil,
--- target: XYPair | nil, --- target: XYPair | nil,
@ -162,23 +161,24 @@ local NextBaseMap <const> = {
[Bases[Third]] = Bases[Home], [Bases[Third]] = Bases[Home],
} }
function newFielder(speed) function newFielder(name, speed)
return { return {
name = name,
speed = speed, speed = speed,
} }
end end
---@type table<string, Fielder> ---@type table<string, Fielder>
local fielders <const> = { local fielders <const> = {
first = newFielder(40), first = newFielder("First", 40),
second = newFielder(40), second = newFielder("Second", 40),
shortstop = newFielder(40), shortstop = newFielder("Shortstop", 40),
third = newFielder(40), third = newFielder("Third", 40),
pitcher = newFielder(30), pitcher = newFielder("Pitcher", 30),
catcher = newFielder(20), catcher = newFielder("Catcher", 20),
left = newFielder(40), left = newFielder("Left", 40),
center = newFielder(40), center = newFielder("Center", 40),
right = newFielder(40), right = newFielder("Right", 40),
} }
local PitcherStartPos <const> = { local PitcherStartPos <const> = {
@ -380,6 +380,64 @@ function score(runnerIndex)
announcer:say("SCORE!") announcer:say("SCORE!")
end end
---@return Base[]
function getForcedOutTargets()
local targets = {}
for _, base in ipairs(Bases) do
local runnerTargetingBase = getRunnerTargeting(base)
if runnerTargetingBase then
targets[#targets + 1] = base
else
return targets
end
end
return targets
end
--- Returns the position,distance of the basest closest to the runner furthest from a base
---@return Base | nil, number | nil
function getBaseOfStrandedRunner()
local farRunnersBase, farDistance
for _, runner in pairs(runners) do
local nearestBase, distance = getNearestOf(Bases, runner.x, runner.y, function(base)
return runner.nextBase == base
end)
if farRunnersBase == nil or farDistance < distance then
farRunnersBase = nearestBase
farDistance = distance
end
end
return farRunnersBase, farDistance
end
--- Returns x,y of the throw target
---@return number|nil, number|nil
function getNextThrowTarget()
-- TODO: Handle missed throws, check for fielders at target, etc.
local targets = getForcedOutTargets()
if #targets ~= 0 then
return targets[#targets].x, targets[#targets].y
end
local baseCloseToStrandedRunner = getBaseOfStrandedRunner()
if baseCloseToStrandedRunner then
return baseCloseToStrandedRunner.x, baseCloseToStrandedRunner.y
end
end
function tryToThrowOut(thrower)
local targetX, targetY = getNextThrowTarget()
if targetX ~= nil and targetY ~= nil then
local nearestFielder = getNearestOf(fielders, targetX, targetY)
nearestFielder.target = xy(targetX, targetY)
if nearestFielder == thrower then
ball.heldBy = thrower
else
throwBall(targetX, targetY, playdate.easingFunctions.linear, nil, true)
end
end
end
function updateFielders() function updateFielders()
local touchingBaseCache = buildCache(function(runner) local touchingBaseCache = buildCache(function(runner)
return isTouchingBase(runner.x, runner.y) return isTouchingBase(runner.x, runner.y)
@ -388,6 +446,7 @@ function updateFielders()
for _, fielder in pairs(fielders) do for _, fielder in pairs(fielders) do
-- TODO: Target unforced runners (or their target bases) for tagging -- TODO: Target unforced runners (or their target bases) for tagging
-- With new Position-based scheme, fielders are now able to set `fielder.target = runner` to track directly -- With new Position-based scheme, fielders are now able to set `fielder.target = runner` to track directly
if fielder.target ~= nil then if fielder.target ~= nil then
local x, y, distance = normalizeVector(fielder.x, fielder.y, fielder.target.x, fielder.target.y) local x, y, distance = normalizeVector(fielder.x, fielder.y, fielder.target.x, fielder.target.y)
@ -396,9 +455,6 @@ function updateFielders()
fielder.y = fielder.y - (y * fielder.speed * deltaSeconds) fielder.y = fielder.y - (y * fielder.speed * deltaSeconds)
else else
fielder.target = nil fielder.target = nil
if fielder.onArrive then
fielder:onArrive()
end
end end
end end
@ -407,22 +463,23 @@ function updateFielders()
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
( -- Force out
touchedBase touchedBase
and runner.prevBase -- Make sure the runner is not 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)
)
or ( -- Tag out
not touchingBaseCache.get(runner)
and distanceBetween(runner.x, runner.y, fielder.x, fielder.y) < TagDistance
)
then then
outRunner(i) outRunner(i)
playdate.timer.new(750, function() playdate.timer.new(750, function()
tryToThrowOut(fielder) tryToThrowOut(fielder)
end) end)
elseif not touchingBaseCache.get(runner) then else
if distanceBetween(runner.x, runner.y, fielder.x, fielder.y) < TagDistance then
outRunner(i)
playdate.timer.new(750, function()
tryToThrowOut(fielder) tryToThrowOut(fielder)
end)
end
end end
end end
end end
@ -485,52 +542,6 @@ function updateRunners(currentRunners)
return runnerMoved return runnerMoved
end end
---@return Base[]
function getForcedOutTargets()
local targets = {}
for _, base in ipairs(Bases) do
local runnerTargetingBase = getRunnerTargeting(base)
if runnerTargetingBase then
targets[#targets + 1] = base
else
return targets
end
end
return targets
end
--- Returns the position,distance of the basest closest to the runner furthest from a base
---@return Base | nil, number | nil
function getBaseOfStrandedRunner()
local farRunnersBase, farDistance
for _, runner in pairs(runners) do
local nearestBase, distance = getNearestOf(Bases, runner.x, runner.y, function(base)
return runner.nextBase == base
end)
if farRunnersBase == nil or farDistance < distance then
farRunnersBase = nearestBase
farDistance = distance
end
end
return farRunnersBase, farDistance
end
--- Returns x,y of the throw target
---@return number|nil, number|nil
function getNextThrowTarget()
-- TODO: Handle missed throws, check for fielders at target, etc.
local targets = getForcedOutTargets()
if #targets ~= 0 then
return targets[#targets].x, targets[#targets].y
end
local baseCloseToStrandedRunner = getBaseOfStrandedRunner()
if baseCloseToStrandedRunner then
return baseCloseToStrandedRunner.x, baseCloseToStrandedRunner.y
end
end
local ResetFieldersAfterSeconds = 2 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
@ -551,20 +562,6 @@ function init()
end) end)
end end
function tryToThrowOut(self)
self.onArrive = nil
local targetX, targetY = getNextThrowTarget()
if targetX ~= nil and targetY ~= nil then
local nearestFielder = getNearestOf(fielders, targetX, targetY)
nearestFielder.target = xy(targetX, targetY)
if nearestFielder == self then
ball.heldBy = self
else
throwBall(targetX, targetY, playdate.easingFunctions.linear, nil, true)
end
end
end
local batAngleDeg local batAngleDeg
function updateBatting() function updateBatting()
@ -617,7 +614,6 @@ function updateBatting()
local chasingFielder = getNearestOf(fielders, ballDestX, ballDestY) local chasingFielder = getNearestOf(fielders, ballDestX, ballDestY)
chasingFielder.target = { x = ballDestX, y = ballDestY } chasingFielder.target = { x = ballDestX, y = ballDestY }
chasingFielder.onArrive = tryToThrowOut
end end
end end