Start supporting less accurate pitches
Fix secondsSinceRunnerLastMove nil bug
This commit is contained in:
parent
d77675b0cb
commit
08a3189780
|
@ -264,7 +264,7 @@ function Baserunning:updateNonBatterRunners(appliedSpeed, forcedOnly, deltaSecon
|
||||||
self.secondsSinceLastRunnerMove = 0
|
self.secondsSinceLastRunnerMove = 0
|
||||||
self:updateForcedRunners()
|
self:updateForcedRunners()
|
||||||
else
|
else
|
||||||
self.secondsSinceLastRunnerMove = self.secondsSinceLastRunnerMove + deltaSeconds
|
self.secondsSinceLastRunnerMove = (self.secondsSinceLastRunnerMove or 0) + deltaSeconds
|
||||||
end
|
end
|
||||||
|
|
||||||
return runnersStillMoving, runnersScored, self.secondsSinceLastRunnerMove
|
return runnersStillMoving, runnersScored, self.secondsSinceLastRunnerMove
|
||||||
|
|
23
src/main.lua
23
src/main.lua
|
@ -196,13 +196,14 @@ end
|
||||||
|
|
||||||
---@param pitchFlyTimeMs number | nil
|
---@param pitchFlyTimeMs number | nil
|
||||||
---@param pitchTypeIndex number | nil
|
---@param pitchTypeIndex number | nil
|
||||||
function Game:pitch(pitchFlyTimeMs, pitchTypeIndex)
|
---@param accuracy number The closer to 1.0, the better
|
||||||
|
function Game:pitch(pitchFlyTimeMs, pitchTypeIndex, accuracy)
|
||||||
self.state.ball:markUncatchable()
|
self.state.ball:markUncatchable()
|
||||||
self.state.ball.heldBy = nil
|
self.state.ball.heldBy = nil
|
||||||
self.state.pitchIsOver = 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](accuracy, self.state.ball)
|
||||||
self.state.ball.xAnimator = current.x
|
self.state.ball.xAnimator = current.x
|
||||||
self.state.ball.yAnimator = current.y or Pitches[1](self.state.ball).y
|
self.state.ball.yAnimator = current.y or Pitches[1](self.state.ball).y
|
||||||
|
|
||||||
|
@ -450,17 +451,17 @@ function Game:returnToPitcher()
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param throwFly number
|
---@param throwFly number
|
||||||
function Game:userPitch(throwFly)
|
function Game:userPitch(throwFly, accuracy)
|
||||||
local aPressed = playdate.buttonIsPressed(playdate.kButtonA)
|
local aPressed = playdate.buttonIsPressed(playdate.kButtonA)
|
||||||
local bPressed = playdate.buttonIsPressed(playdate.kButtonB)
|
local bPressed = playdate.buttonIsPressed(playdate.kButtonB)
|
||||||
if not aPressed and not bPressed then
|
if not aPressed and not bPressed then
|
||||||
self:pitch(throwFly, 1)
|
self:pitch(throwFly, 1, accuracy)
|
||||||
elseif aPressed and not bPressed then
|
elseif aPressed and not bPressed then
|
||||||
self:pitch(throwFly, 2)
|
self:pitch(throwFly, 2, accuracy)
|
||||||
elseif not aPressed and bPressed then
|
elseif not aPressed and bPressed then
|
||||||
self:pitch(throwFly, 3)
|
self:pitch(throwFly, 3, accuracy)
|
||||||
elseif aPressed and bPressed then
|
elseif aPressed and bPressed then
|
||||||
self:pitch(throwFly, 4)
|
self:pitch(throwFly, 4, accuracy)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -519,15 +520,15 @@ function Game:updateGameState()
|
||||||
self:updateBatting(self.state.batAngleDeg, batSpeed)
|
self:updateBatting(self.state.batAngleDeg, batSpeed)
|
||||||
|
|
||||||
-- Walk batter to the plate
|
-- Walk batter to the plate
|
||||||
self.baserunning:updateRunner(self.baserunning.batter, nil, crankLimited, self.state.deltaSeconds)
|
self.baserunning:updateRunner(self.baserunning.batter, nil, userOnOffense and crankLimited or 0, self.state.deltaSeconds)
|
||||||
|
|
||||||
if pitchTracker.secondsSinceLastPitch > C.PitchAfterSeconds then
|
if pitchTracker.secondsSinceLastPitch > C.PitchAfterSeconds then
|
||||||
if userOnDefense then
|
if userOnDefense then
|
||||||
local powerRatio, isPerfect = throwMeter:readThrow(crankChange)
|
local powerRatio, accuracy, isPerfect = throwMeter:readThrow(crankChange)
|
||||||
if powerRatio then
|
if powerRatio then
|
||||||
local throwFly = C.PitchFlyMs / powerRatio
|
local throwFly = C.PitchFlyMs / powerRatio
|
||||||
if throwFly and not self:buttonControlledThrow(throwFly, true) then
|
if throwFly and not self:buttonControlledThrow(throwFly, true) then
|
||||||
self:userPitch(throwFly)
|
self:userPitch(throwFly, accuracy)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -547,7 +548,7 @@ function Game:updateGameState()
|
||||||
end
|
end
|
||||||
|
|
||||||
if userOnDefense then
|
if userOnDefense then
|
||||||
local powerRatio, isPerfect = throwMeter:readThrow(crankChange)
|
local powerRatio, accuracy, isPerfect = throwMeter:readThrow(crankChange)
|
||||||
if powerRatio then
|
if powerRatio then
|
||||||
local throwFly = C.PitchFlyMs / powerRatio
|
local throwFly = C.PitchFlyMs / powerRatio
|
||||||
if throwFly then
|
if throwFly then
|
||||||
|
|
|
@ -18,6 +18,7 @@ function Npc.new(runners, fielders)
|
||||||
}, { __index = Npc })
|
}, { __index = Npc })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- TODO: FAR more nuanced NPC batting.
|
||||||
---@param ball XyPair
|
---@param ball XyPair
|
||||||
---@param pitchIsOver boolean
|
---@param pitchIsOver boolean
|
||||||
---@param deltaSec number
|
---@param deltaSec number
|
||||||
|
|
|
@ -4,35 +4,47 @@
|
||||||
---@type pd_graphics_lib
|
---@type pd_graphics_lib
|
||||||
local gfx <const> = playdate.graphics
|
local gfx <const> = playdate.graphics
|
||||||
|
|
||||||
|
local StrikeZoneWidth <const> = C.StrikeZoneEndX - C.StrikeZoneStartX
|
||||||
|
|
||||||
|
-- TODO? Also degrade speed
|
||||||
|
function getPitchMissBy(accuracy)
|
||||||
|
accuracy = accuracy or 1.0
|
||||||
|
local missBy = (1 - accuracy) * StrikeZoneWidth * 3
|
||||||
|
if math.random() > 0.5 then
|
||||||
|
missBy = missBy * -1
|
||||||
|
end
|
||||||
|
return missBy
|
||||||
|
end
|
||||||
|
|
||||||
---@type Pitch[]
|
---@type Pitch[]
|
||||||
Pitches = {
|
Pitches = {
|
||||||
-- Fastball
|
-- Fastball
|
||||||
function()
|
function(accuracy)
|
||||||
return {
|
return {
|
||||||
x = gfx.animator.new(0, C.PitchStart.x, C.PitchStart.x, playdate.easingFunctions.linear),
|
x = gfx.animator.new(0, C.PitchStart.x, getPitchMissBy(accuracy) + C.PitchStart.x, playdate.easingFunctions.linear),
|
||||||
y = gfx.animator.new(C.PitchFlyMs / 1.3, C.PitchStart.y, C.PitchEndY, playdate.easingFunctions.linear),
|
y = gfx.animator.new(C.PitchFlyMs / 1.3, C.PitchStart.y, C.PitchEndY, playdate.easingFunctions.linear),
|
||||||
}
|
}
|
||||||
end,
|
end,
|
||||||
-- Curve ball
|
-- Curve ball
|
||||||
function()
|
function(accuracy)
|
||||||
return {
|
return {
|
||||||
x = gfx.animator.new(C.PitchFlyMs, C.PitchStart.x + 20, C.PitchStart.x, utils.easingHill),
|
x = gfx.animator.new(C.PitchFlyMs, getPitchMissBy(accuracy) + C.PitchStart.x + 20, C.PitchStart.x, utils.easingHill),
|
||||||
y = gfx.animator.new(C.PitchFlyMs, C.PitchStart.y, C.PitchEndY, playdate.easingFunctions.linear),
|
y = gfx.animator.new(C.PitchFlyMs, C.PitchStart.y, C.PitchEndY, playdate.easingFunctions.linear),
|
||||||
}
|
}
|
||||||
end,
|
end,
|
||||||
-- Slider
|
-- Slider
|
||||||
function()
|
function(accuracy)
|
||||||
return {
|
return {
|
||||||
x = gfx.animator.new(C.PitchFlyMs, C.PitchStart.x - 20, C.PitchStart.x, utils.easingHill),
|
x = gfx.animator.new(C.PitchFlyMs, getPitchMissBy(accuracy) + C.PitchStart.x - 20, C.PitchStart.x, utils.easingHill),
|
||||||
y = gfx.animator.new(C.PitchFlyMs, C.PitchStart.y, C.PitchEndY, playdate.easingFunctions.linear),
|
y = gfx.animator.new(C.PitchFlyMs, C.PitchStart.y, C.PitchEndY, playdate.easingFunctions.linear),
|
||||||
}
|
}
|
||||||
end,
|
end,
|
||||||
-- Wobbbleball
|
-- Wobbbleball
|
||||||
function(ball)
|
function(accuracy, ball)
|
||||||
return {
|
return {
|
||||||
x = {
|
x = {
|
||||||
currentValue = function()
|
currentValue = function()
|
||||||
return C.PitchStart.x + (10 * math.sin((ball.yAnimator:currentValue() - C.PitchStart.y) / 10))
|
return getPitchMissBy(accuracy) + C.PitchStart.x + (10 * math.sin((ball.yAnimator:currentValue() - C.PitchStart.y) / 10))
|
||||||
end,
|
end,
|
||||||
reset = function() end,
|
reset = function() end,
|
||||||
},
|
},
|
||||||
|
@ -117,14 +129,20 @@ local crankQueue = {}
|
||||||
|
|
||||||
--- Returns nil when a throw is NOT requested.
|
--- Returns nil when a throw is NOT requested.
|
||||||
---@param chargeAmount number
|
---@param chargeAmount number
|
||||||
---@return number | nil powerRatio, boolean isPerfect
|
---@return number | nil powerRatio, number | nil accuracy, boolean isPerfect
|
||||||
function throwMeter:readThrow(chargeAmount)
|
function throwMeter:readThrow(chargeAmount)
|
||||||
local ret = self:applyCharge(chargeAmount)
|
local ret = self:applyCharge(chargeAmount)
|
||||||
if ret then
|
if ret then
|
||||||
local ratio = ret / self.idealPower
|
local ratio = ret / self.idealPower
|
||||||
return ratio, math.abs(ratio - 1) < 0.05
|
local accuracy
|
||||||
|
if ratio >= 1 then
|
||||||
|
accuracy = 1 / ratio / 2
|
||||||
|
else
|
||||||
|
accuracy = 1 -- Accuracy is perfect on slow throws
|
||||||
|
end
|
||||||
|
return ratio, accuracy, math.abs(ratio - 1) < 0.05
|
||||||
end
|
end
|
||||||
return nil, false
|
return nil, nil, false
|
||||||
end
|
end
|
||||||
|
|
||||||
--- If (within approx. a third of a second) the crank has moved more than 45 degrees, call that a throw.
|
--- If (within approx. a third of a second) the crank has moved more than 45 degrees, call that a throw.
|
||||||
|
|
Loading…
Reference in New Issue