Move more logic into field.lua

This commit is contained in:
Sage Vaillancourt 2025-02-08 18:28:17 -05:00
parent d85db79e52
commit 80c15161e3
5 changed files with 78 additions and 58 deletions

View File

@ -94,9 +94,9 @@ C.ThrowMeterDrainPerSec = 150
--- Controls how hard the ball can be hit, and --- Controls how hard the ball can be hit, and
--- how fast the ball can be thrown. --- how fast the ball can be thrown.
C.CrankPower = 10 C.CrankPower = 3
--- How fast baserunners move after a walk --- How fast baserunners move after a walk
C.WalkedRunnerSpeed = 10 C.WalkedRunnerSpeed = 10
C.ResetFieldersAfterSeconds = 3 C.ResetFieldersAfterSeconds = 7

View File

@ -54,3 +54,35 @@ function Field.resetFielderPositions(self, fromOffTheField)
self.fielders.center.target = utils.xy(C.Center.x, C.Screen.H * -0.4) self.fielders.center.target = utils.xy(C.Center.x, C.Screen.H * -0.4)
self.fielders.right.target = utils.xy(C.Screen.W * 2, self.fielders.left.target.y) self.fielders.right.target = utils.xy(C.Screen.W * 2, self.fielders.left.target.y)
end end
---@param fielder Fielder
---@param ballPos XYPair
---@return boolean isHoldingBall
local function updateFielder(deltaSeconds, fielder, ballPos)
if fielder.target ~= nil then
if not utils.moveAtSpeed(fielder, fielder.speed * deltaSeconds, fielder.target) then
fielder.target = nil
end
end
local isTouchingBall = utils.distanceBetweenPoints(fielder, ballPos) < C.BallCatchHitbox
if not isTouchingBall then
return false
end
return true
end
---@param ball XYPair
---@return Fielder | nil fielderTouchingBall nil if no fielder is currently touching the ball
function Field.updateFielders(self, ball, deltaSeconds)
local fielderTouchingBall
for _, fielder in pairs(self.fielders) do
local isHoldingBall = updateFielder(deltaSeconds, fielder, ball)
if isHoldingBall then
fielderTouchingBall = fielder
end
end
return fielderTouchingBall
end

View File

@ -85,7 +85,7 @@ local teams <const> = {
}, },
} }
local PlayerTeam <const> = teams.away local PlayerTeam <const> = teams.home
local battingTeam = teams.away local battingTeam = teams.away
local outs = 0 local outs = 0
local inning = 1 local inning = 1
@ -206,25 +206,6 @@ local function pitch(pitchFlyTimeMs, pitchTypeIndex)
secondsSincePitchAllowed = 0 secondsSincePitchAllowed = 0
end end
--- Returns the base being touched by the player at (x,y), or nil, if no base is being touched
---@param x number
---@param y number
---@return Base | nil
local function isTouchingBase(x, y)
return utils.first(C.Bases, function(base)
return utils.distanceBetween(x, y, base.x, base.y) < C.BaseHitbox
end)
end
--- Returns true only if the given point is touching the ball at its current position
---@param x number
---@param y number
---@return boolean, number
local function isTouchingBall(x, y)
local ballDistance = utils.distanceBetween(x, y, ball.x, ball.y)
return ballDistance < C.BallCatchHitbox, ballDistance
end
---@param base Base ---@param base Base
---@return Runner | nil ---@return Runner | nil
local function getRunnerWithNextBase(base) local function getRunnerWithNextBase(base)
@ -307,7 +288,7 @@ local function score(runnerIndex)
end end
---@return Base[] ---@return Base[]
local function getForcedOutTargets() local function npcGetForcedOutTargets()
local targets = {} local targets = {}
for _, base in ipairs(C.Bases) do for _, base in ipairs(C.Bases) do
local runnerTargetingBase = getRunnerWithNextBase(base) local runnerTargetingBase = getRunnerWithNextBase(base)
@ -339,9 +320,9 @@ end
--- Returns x,y of the out target --- Returns x,y of the out target
---@return number|nil, number|nil ---@return number|nil, number|nil
local function getNextOutTarget() local function npcGetNextOutTarget()
-- TODO: Handle missed throws, check for fielders at target, etc. -- TODO: Handle missed throws, check for fielders at target, etc.
local targets = getForcedOutTargets() local targets = npcGetForcedOutTargets()
if #targets ~= 0 then if #targets ~= 0 then
return targets[#targets].x, targets[#targets].y return targets[#targets].x, targets[#targets].y
end end
@ -353,8 +334,8 @@ local function getNextOutTarget()
end end
---@param fielder Fielder ---@param fielder Fielder
local function tryToMakeAnOut(fielder) local function npcTryToMakeAnOut(fielder)
local targetX, targetY = getNextOutTarget() local targetX, targetY = npcGetNextOutTarget()
if targetX ~= nil and targetY ~= nil then if targetX ~= nil and targetY ~= nil then
local nearestFielder = utils.getNearestOf(Field.fielders, targetX, targetY) local nearestFielder = utils.getNearestOf(Field.fielders, targetX, targetY)
nearestFielder.target = utils.xy(targetX, targetY) nearestFielder.target = utils.xy(targetX, targetY)
@ -403,10 +384,10 @@ local function buttonControlledThrow(thrower, throwFlyMs, forbidThrowHome)
end end
local function outEligibleRunners(fielder) local function outEligibleRunners(fielder)
local touchedBase = isTouchingBase(fielder.x, fielder.y) local touchedBase = utils.isTouchingBase(fielder.x, fielder.y)
local didOutRunner = false local didOutRunner = false
for i, runner in pairs(runners) do for i, runner in pairs(runners) do
local runnerOnBase = isTouchingBase(runner.x, runner.y) local runnerOnBase = utils.isTouchingBase(runner.x, runner.y)
if -- Force out 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
@ -429,34 +410,10 @@ local function updateNpcFielder(fielder, outedSomeRunner)
end end
if outedSomeRunner then if outedSomeRunner then
playdate.timer.new(750, function() playdate.timer.new(750, function()
tryToMakeAnOut(fielder) npcTryToMakeAnOut(fielder)
end) end)
else else
tryToMakeAnOut(fielder) npcTryToMakeAnOut(fielder)
end
end
---@param fielder Fielder
local function updateFielder(fielder)
if fielder.target ~= nil then
if not utils.moveAtSpeed(fielder, fielder.speed * deltaSeconds, fielder.target) then
fielder.target = nil
end
end
if not isTouchingBall(fielder.x, fielder.y) then
return
end
local outedSomeRunner = outEligibleRunners(fielder)
if playerIsOn(C.Sides.defense) then
local throwFly = readThrow()
if throwFly then
buttonControlledThrow(Field.fielders.pitcher, throwFly)
end
else
updateNpcFielder(fielder, outedSomeRunner)
end end
end end
@ -508,6 +465,7 @@ local function updateRunner(runner, runnerIndex, appliedSpeed)
local autoRun = (nearestBaseDistance > 40 or runner.forcedTo) and mult * autoRunSpeed local autoRun = (nearestBaseDistance > 40 or runner.forcedTo) and mult * autoRunSpeed
or nearestBaseDistance < 5 and 0 or nearestBaseDistance < 5 and 0
or (nearestBase == runner.nextBase and autoRunSpeed or -1 * autoRunSpeed) or (nearestBase == runner.nextBase and autoRunSpeed or -1 * autoRunSpeed)
mult = autoRun + (appliedSpeed / 20) mult = autoRun + (appliedSpeed / 20)
runner.x = runner.x - (x * mult) runner.x = runner.x - (x * mult)
runner.y = runner.y - (y * mult) runner.y = runner.y - (y * mult)
@ -731,9 +689,20 @@ local function updateGameState()
end end
end end
for _, fielder in pairs(Field.fielders) do local fielderHoldingBall = Field:updateFielders(ball, deltaSeconds)
updateFielder(fielder)
if fielderHoldingBall then
local outedSomeRunner = outEligibleRunners(fielderHoldingBall)
if playerOnDefense then
local throwFly = readThrow()
if throwFly then
buttonControlledThrow(Field.fielders.pitcher, throwFly)
end end
else
updateNpcFielder(fielder, outedSomeRunner)
end
end
walkAwayOutRunners() walkAwayOutRunners()
end end

View File

@ -23,7 +23,7 @@ function npc.runningSpeed(runners)
if #runners == 0 then if #runners == 0 then
return 0 return 0
end end
local touchedBase = isTouchingBase(runners[1].x, runners[1].y) local touchedBase = utils.isTouchingBase(runners[1].x, runners[1].y)
if not touchedBase or touchedBase == C.Bases[C.Home] then if not touchedBase or touchedBase == C.Bases[C.Home] then
return 10 return 10
end end

View File

@ -102,6 +102,15 @@ function utils.distanceBetween(x1, y1, x2, y2)
return sqrt((x * x) + (y * y)), x, y return sqrt((x * x) + (y * y)), x, y
end end
---@param point1 XYPair
---@param point2 XYPair
---@return number distance, number x, number y
function utils.distanceBetweenPoints(point1, point2)
local x = point1.x - point2.x
local y = point1.y - point2.y
return sqrt((x * x) + (y * y)), x, y
end
---@return number distance, number x, number y, number z ---@return number distance, number x, number y, number z
function utils.distanceBetweenZ(x1, y1, z1, x2, y2, z2) function utils.distanceBetweenZ(x1, y1, z1, x2, y2, z2)
local x = x1 - x2 local x = x1 - x2
@ -123,6 +132,16 @@ function utils.newRunner(runners)
return new return new
end end
--- Returns the base being touched by the player at (x,y), or nil, if no base is being touched
---@param x number
---@param y number
---@return Base | nil
function utils.isTouchingBase(x, y)
return utils.first(C.Bases, function(base)
return utils.distanceBetween(x, y, base.x, base.y) < C.BaseHitbox
end)
end
--- Returns true only if the point is below the given line, within the x bounds of said line, and above the bottomBound --- Returns true only if the point is below the given line, within the x bounds of said line, and above the bottomBound
--- @return boolean --- @return boolean
function utils.pointDirectlyUnderLine(pointX, pointY, lineX1, lineY1, lineX2, lineY2, bottomBound) function utils.pointDirectlyUnderLine(pointX, pointY, lineX1, lineY1, lineX2, lineY2, bottomBound)