Pitcher can throw to bases.
Logic should be re-usable generally for throwing between fielders.
This commit is contained in:
parent
57625a9b80
commit
8319b554ec
91
src/main.lua
91
src/main.lua
|
@ -94,16 +94,16 @@ local Pitches <const> = {
|
||||||
x = gfx.animator.new(0, PitchStartX, PitchStartX, playdate.easingFunctions.linear),
|
x = gfx.animator.new(0, PitchStartX, PitchStartX, playdate.easingFunctions.linear),
|
||||||
y = gfx.animator.new(PitchFlyMs / 1.3, PitchStartY, PitchEndY, 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
|
-- Curve ball
|
||||||
{
|
{
|
||||||
x = gfx.animator.new(PitchFlyMs, PitchStartX + 20, PitchStartX, utils.easingHill),
|
x = gfx.animator.new(PitchFlyMs, PitchStartX + 20, PitchStartX, utils.easingHill),
|
||||||
y = gfx.animator.new(PitchFlyMs, PitchStartY, PitchEndY, playdate.easingFunctions.linear),
|
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
|
-- Wobbbleball
|
||||||
{
|
{
|
||||||
x = {
|
x = {
|
||||||
|
@ -322,11 +322,12 @@ local secondsSincePitchAllowed = -5
|
||||||
local catcherThrownBall = false
|
local catcherThrownBall = false
|
||||||
|
|
||||||
---@param pitchFlyTimeMs number | nil
|
---@param pitchFlyTimeMs number | nil
|
||||||
function pitch(pitchFlyTimeMs)
|
---@param pitchTypeIndex number | nil
|
||||||
|
function pitch(pitchFlyTimeMs, pitchTypeIndex)
|
||||||
catcherThrownBall = false
|
catcherThrownBall = false
|
||||||
offenseMode = Offense.batting
|
offenseMode = Offense.batting
|
||||||
|
|
||||||
local current = Pitches[math.random(#Pitches)]
|
local current = Pitches[pitchTypeIndex or math.random(#Pitches)]
|
||||||
ballAnimatorX = current.x
|
ballAnimatorX = current.x
|
||||||
ballAnimatorY = current.y or Pitches[1].y
|
ballAnimatorY = current.y or Pitches[1].y
|
||||||
|
|
||||||
|
@ -467,12 +468,14 @@ end
|
||||||
function getBaseOfStrandedRunner()
|
function getBaseOfStrandedRunner()
|
||||||
local farRunnersBase, farDistance
|
local farRunnersBase, farDistance
|
||||||
for _, runner in pairs(runners) do
|
for _, runner in pairs(runners) do
|
||||||
|
if runner ~= batter then
|
||||||
local nearestBase, distance = utils.getNearestOf(Bases, runner.x, runner.y)
|
local nearestBase, distance = utils.getNearestOf(Bases, runner.x, runner.y)
|
||||||
if farRunnersBase == nil or farDistance < distance then
|
if farRunnersBase == nil or farDistance < distance then
|
||||||
farRunnersBase = nearestBase
|
farRunnersBase = nearestBase
|
||||||
farDistance = distance
|
farDistance = distance
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return farRunnersBase, farDistance
|
return farRunnersBase, farDistance
|
||||||
end
|
end
|
||||||
|
@ -721,10 +724,10 @@ function walkAwayOutRunners()
|
||||||
end
|
end
|
||||||
|
|
||||||
local npcBatDeg = 0
|
local npcBatDeg = 0
|
||||||
local NpcBatSpeed <const> = 1200
|
local NpcBatSpeed <const> = 1500
|
||||||
|
|
||||||
function npcBatAngle()
|
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)
|
npcBatDeg = npcBatDeg + (deltaSeconds * NpcBatSpeed)
|
||||||
else
|
else
|
||||||
npcBatDeg = 200
|
npcBatDeg = 200
|
||||||
|
@ -742,21 +745,51 @@ function npcRunningSpeed()
|
||||||
end
|
end
|
||||||
local touchedBase = isTouchingBase(runners[1].x, runners[1].y)
|
local touchedBase = isTouchingBase(runners[1].x, runners[1].y)
|
||||||
if not touchedBase or touchedBase == Bases[Home] then
|
if not touchedBase or touchedBase == Bases[Home] then
|
||||||
return 35
|
return 25
|
||||||
end
|
end
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local pitchMeter = 0
|
local throwMeter = 0
|
||||||
local PitchMeterLimit = 25
|
local PitchMeterLimit = 25
|
||||||
|
|
||||||
function readPitch()
|
function readThrow()
|
||||||
if pitchMeter > PitchMeterLimit then
|
if throwMeter > PitchMeterLimit then
|
||||||
return (PitchFlyMs / (pitchMeter / PitchMeterLimit))
|
return (PitchFlyMs / (throwMeter / PitchMeterLimit))
|
||||||
end
|
end
|
||||||
return nil
|
return nil
|
||||||
end
|
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()
|
function updateGameState()
|
||||||
deltaSeconds = playdate.getElapsedTime() or 0
|
deltaSeconds = playdate.getElapsedTime() or 0
|
||||||
playdate.resetElapsedTime()
|
playdate.resetElapsedTime()
|
||||||
|
@ -778,24 +811,31 @@ function updateGameState()
|
||||||
throwBall(PitchStartX, PitchStartY, playdate.easingFunctions.linear, nil, true)
|
throwBall(PitchStartX, PitchStartY, playdate.easingFunctions.linear, nil, true)
|
||||||
catcherThrownBall = true
|
catcherThrownBall = true
|
||||||
else
|
else
|
||||||
pitchMeter = 0
|
throwMeter = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
if not playerOnOffense then
|
if not playerOnOffense then
|
||||||
pitchMeter = math.max(0, pitchMeter - (deltaSeconds * 150))
|
throwMeter = math.max(0, throwMeter - (deltaSeconds * 150))
|
||||||
pitchMeter = pitchMeter + crankChange
|
throwMeter = throwMeter + crankChange
|
||||||
if pitchMeter > PitchMeterLimit then
|
|
||||||
printTable({ pitchMeter = pitchMeter })
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if secondsSincePitchAllowed > PitchAfterSeconds then
|
if secondsSincePitchAllowed > PitchAfterSeconds then
|
||||||
if playerOnOffense then
|
if playerOnOffense then
|
||||||
pitch(PitchFlyMs)
|
pitch(PitchFlyMs)
|
||||||
else
|
else
|
||||||
local pitchFly = readPitch()
|
local throwFly = readThrow()
|
||||||
if pitchFly then
|
if throwFly and not buttonControlledThrow(fielders.pitcher, throwFly, true) then
|
||||||
pitch(pitchFly)
|
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
|
end
|
||||||
end
|
end
|
||||||
|
@ -814,10 +854,12 @@ function updateGameState()
|
||||||
throwBall(PitchStartX, PitchStartY, playdate.easingFunctions.linear, nil, true)
|
throwBall(PitchStartX, PitchStartY, playdate.easingFunctions.linear, nil, true)
|
||||||
resetFielderPositions()
|
resetFielderPositions()
|
||||||
offenseMode = Offense.batting
|
offenseMode = Offense.batting
|
||||||
|
if not batter then
|
||||||
batter = newRunner()
|
batter = newRunner()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
updateFielders()
|
updateFielders()
|
||||||
walkAwayOutRunners()
|
walkAwayOutRunners()
|
||||||
|
@ -829,11 +871,10 @@ function drawMinimap() end
|
||||||
---@param fielder Fielder
|
---@param fielder Fielder
|
||||||
---@return boolean isHoldingBall
|
---@return boolean isHoldingBall
|
||||||
function drawFielderGlove(fielder)
|
function drawFielderGlove(fielder)
|
||||||
printTable({ ballFloatValue = ballFloatAnimator:currentValue() })
|
|
||||||
local distanceFromBall =
|
local distanceFromBall =
|
||||||
utils.distanceBetweenZ(fielder.x, fielder.y, 0, ball.x, ball.y, ballFloatAnimator:currentValue())
|
utils.distanceBetweenZ(fielder.x, fielder.y, 0, ball.x, ball.y, ballFloatAnimator:currentValue())
|
||||||
local shoulderX, shoulderY = fielder.x + 10, fielder.y + FielderDanceAnimator:currentValue() + 5
|
local shoulderX, shoulderY = fielder.x + 10, fielder.y + FielderDanceAnimator:currentValue() + 5
|
||||||
if distanceFromBall > 30 then
|
if distanceFromBall > 20 then
|
||||||
Glove:draw(shoulderX, shoulderY)
|
Glove:draw(shoulderX, shoulderY)
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
|
|
|
@ -43,8 +43,8 @@ end
|
||||||
---@param y2 number
|
---@param y2 number
|
||||||
---@return number x, number y, number distance
|
---@return number x, number y, number distance
|
||||||
function utils.normalizeVector(x1, y1, x2, y2)
|
function utils.normalizeVector(x1, y1, x2, y2)
|
||||||
local distance, a, b = utils.distanceBetween(x1, y1, x2, y2)
|
local distance, x, y = utils.distanceBetween(x1, y1, x2, y2)
|
||||||
return a / distance, b / distance, distance
|
return x / distance, y / distance, distance
|
||||||
end
|
end
|
||||||
|
|
||||||
---@generic T
|
---@generic T
|
||||||
|
@ -63,17 +63,17 @@ end
|
||||||
|
|
||||||
---@return number distance, number x, number y
|
---@return number distance, number x, number y
|
||||||
function utils.distanceBetween(x1, y1, x2, y2)
|
function utils.distanceBetween(x1, y1, x2, y2)
|
||||||
local a = x1 - x2
|
local x = x1 - x2
|
||||||
local b = y1 - y2
|
local y = y1 - y2
|
||||||
return math.sqrt((a * a) + (b * b)), a, b
|
return math.sqrt((x * x) + (y * y)), x, y
|
||||||
end
|
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)
|
function utils.distanceBetweenZ(x1, y1, z1, x2, y2, z2)
|
||||||
local a = x1 - x2
|
local x = x1 - x2
|
||||||
local b = y1 - y2
|
local y = y1 - y2
|
||||||
local c = z1 - z2
|
local z = z1 - z2
|
||||||
return math.sqrt((a * a) + (b * b) + (c * c)), a, b
|
return math.sqrt((x * x) + (y * y) + (z * z)), x, y, z
|
||||||
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
|
||||||
|
|
Loading…
Reference in New Issue