From 7b49603760d45fe9805d4fb834a188f356a34386 Mon Sep 17 00:00:00 2001 From: Sage Vaillancourt Date: Fri, 21 Feb 2025 15:05:14 -0500 Subject: [PATCH] Fix flickering on return-to-pitcher. Some linting. Prevent runners "sticking" to bases during walk/homeRun sequences. Tweak logo to remove some trailing pixels. --- src/action-queue.lua | 10 +++++ src/baserunning.lua | 16 +++++--- src/draw/fans.lua | 2 +- src/draw/throw-meter.lua | 2 +- src/fielding.lua | 2 +- src/graphics.lua | 4 +- src/images/game/GameLogo.png | Bin 1575 -> 5313 bytes src/main.lua | 70 ++++++++++++++++++++++++----------- src/pitching.lua | 28 +++++++++++--- 9 files changed, 94 insertions(+), 40 deletions(-) diff --git a/src/action-queue.lua b/src/action-queue.lua index 2571249..efe6956 100644 --- a/src/action-queue.lua +++ b/src/action-queue.lua @@ -25,6 +25,16 @@ function actionQueue:upsert(id, maxTimeMs, action) } end +function actionQueue:newOnly(id, maxTimeMs, action) + if self.queue[id] then + return + end + self.queue[id] = { + coroutine = coroutine.create(action), + expireTimeMs = maxTimeMs + playdate.getCurrentTimeMilliseconds(), + } +end + --- Must be called on every playdate.update() to check for (and run) any waiting tasks. --- Actions that return NeedsMoreTime will not be removed from the queue unless they have expired. function actionQueue:runWaiting(deltaSeconds) diff --git a/src/baserunning.lua b/src/baserunning.lua index 7a91df5..88d30a8 100644 --- a/src/baserunning.lua +++ b/src/baserunning.lua @@ -179,7 +179,7 @@ end ---@param appliedSpeed number ---@param deltaSeconds number ---@return boolean runnerMoved, boolean runnerScored -function Baserunning:updateRunner(runner, runnerIndex, appliedSpeed, deltaSeconds) +function Baserunning:updateRunner(runner, runnerIndex, appliedSpeed, isAutoRun, deltaSeconds) local autoRunSpeed = 20 * deltaSeconds if not runner or not runner.nextBase then @@ -226,9 +226,12 @@ function Baserunning:updateRunner(runner, runnerIndex, appliedSpeed, deltaSecond -- TODO: Make this less "sticky" for the user. -- Currently it can be a little hard to run *past* a base. - local autoRun = (nearestBaseDistance > 40 or runner.forcedTo) and mult * autoRunSpeed - or nearestBaseDistance < 5 and 0 - or (nearestBase == runner.nextBase and autoRunSpeed or -1 * autoRunSpeed) + local autoRun = 0 + if not isAutoRun then + autoRun = (nearestBaseDistance > 40 or runner.forcedTo) and mult * autoRunSpeed + or nearestBaseDistance < 5 and 0 + or (nearestBase == runner.nextBase and autoRunSpeed or -1 * autoRunSpeed) + end mult = autoRun + (appliedSpeed / 20) runner.x = runner.x - (x * mult) @@ -240,8 +243,9 @@ end --- Update non-batter runners. --- Returns true only if at least one of the given runners moved during this update ---@param appliedSpeed number | fun(runner: Runner): number +---@param isAutoRun boolean If true, does not attempt to hug the bases ---@return boolean runnersStillMoving, number runnersScored, number secondsSinceLastMove -function Baserunning:updateNonBatterRunners(appliedSpeed, forcedOnly, deltaSeconds) +function Baserunning:updateNonBatterRunners(appliedSpeed, forcedOnly, isAutoRun, deltaSeconds) local runnersStillMoving = false local runnersScored = 0 @@ -253,7 +257,7 @@ function Baserunning:updateNonBatterRunners(appliedSpeed, forcedOnly, deltaSecon if speedIsFunction then speed = appliedSpeed(runner) end - local thisRunnerMoved, thisRunnerScored = self:updateRunner(runner, runnerIndex, speed, deltaSeconds) + local thisRunnerMoved, thisRunnerScored = self:updateRunner(runner, runnerIndex, speed, isAutoRun, deltaSeconds) runnersStillMoving = runnersStillMoving or thisRunnerMoved if thisRunnerScored then runnersScored = runnersScored + 1 diff --git a/src/draw/fans.lua b/src/draw/fans.lua index 5e6d9df..523458c 100644 --- a/src/draw/fans.lua +++ b/src/draw/fans.lua @@ -1,4 +1,4 @@ -local gfx , C = playdate.graphics, C +local gfx = playdate.graphics fans = {} diff --git a/src/draw/throw-meter.lua b/src/draw/throw-meter.lua index cd0973e..44502cc 100644 --- a/src/draw/throw-meter.lua +++ b/src/draw/throw-meter.lua @@ -15,7 +15,7 @@ function throwMeter:draw(x, y) if self.lastReadThrow then -- TODO: If meter has moved to a new fielder, empty it. local ratio = 1 - if not wasPerfect then + if not self.wasPerfect then ratio = (self.lastReadThrow - throwMeter.MinCharge) / (self.idealPower - throwMeter.MinCharge) end local height = ThrowMeterHeight * ratio diff --git a/src/fielding.lua b/src/fielding.lua index a99a67f..47c4e02 100644 --- a/src/fielding.lua +++ b/src/fielding.lua @@ -31,7 +31,7 @@ local function newFielder(name, speed) return { name = name, speed = speed * C.FielderRunMult, - spriteIndex = math.random(#HomeTeamSpriteGroup) + spriteIndex = math.random(#HomeTeamSpriteGroup), } end diff --git a/src/graphics.lua b/src/graphics.lua index 7c82300..c9e741e 100644 --- a/src/graphics.lua +++ b/src/graphics.lua @@ -32,12 +32,10 @@ function blipper.new(msInterval, spriteCollection) blinker:start() return { blinker = blinker, - smiling = smiling, - lowHat = lowHat, draw = function(self, disableBlipping, x, y, hasSpriteIndex) local spriteBundle = spriteCollection[hasSpriteIndex.spriteIndex] local currentImage = (disableBlipping or self.blinker.on) and spriteBundle.lowHat or spriteBundle.smiling - local offsetY = currentImage == lowHat and -1 or 0 + local offsetY = currentImage == spriteBundle.lowHat and -1 or 0 currentImage:draw(x, y + offsetY) end, } diff --git a/src/images/game/GameLogo.png b/src/images/game/GameLogo.png index 3c231b8892120fdfe5c07e4a8aa5bb7055c036d8..1d3907f6452708edf7f90f57c0be6d12b8f09b2f 100644 GIT binary patch literal 5313 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 Yoa4Cf&>3}11d&+8L7~Emz=Tcz1vCSx-v9sr delta 496 zcmV>%Qh zp*q<`MZ~FAp$HX1t&x^1SD2{D^n6+^EO(1!qmn17X-Wz0!Z3ZCQZ9zMR_ z#dwzYxj#q0nztC>6N%%@Fm2)u;^|G>;Ji;9VI^55J|`YG>4L2;D7MDTdOcR(Mk#@fZ&Vce2fC2 zU7%TaobO}DX`TT7XW&Zj_^Sg+c*% zKcjET0fV(3_C8J@fDCn&x&aOjfw3ZGuY0_^rx3fhf6ui0`vGUJa-vb@*Qb+I z5Hbi25()|Fq)ca%ju0pT|FgFc(*r0s!F!01#dP2 C.PitchAfterSeconds then if userOnDefense then - local powerRatio, accuracy, isPerfect = throwMeter:readThrow(crankChange) + local powerRatio, accuracy = throwMeter:readThrow(crankChange) if powerRatio then local throwFly = C.PitchFlyMs / powerRatio if throwFly and not self:buttonControlledThrow(throwFly, true) then @@ -541,7 +560,7 @@ function Game:updateGameState() or function(runner) return self.npc:runningSpeed(runner, self.state.ball) end - local _, secondsSinceLastRunnerMove = self:updateNonBatterRunners(appliedSpeed, false) + local _, secondsSinceLastRunnerMove = self:updateNonBatterRunners(appliedSpeed, false, false) if secondsSinceLastRunnerMove > C.ResetFieldersAfterSeconds then -- End of play. Throw the ball back to the pitcher self.state.offenseState = C.Offense.batting @@ -549,7 +568,7 @@ function Game:updateGameState() end if userOnDefense then - local powerRatio, accuracy, isPerfect = throwMeter:readThrow(crankChange) + local powerRatio = throwMeter:readThrow(crankChange) if powerRatio then local throwFly = C.PitchFlyMs / powerRatio if throwFly then @@ -558,11 +577,11 @@ function Game:updateGameState() end end elseif self.state.offenseState == C.Offense.walking then - if not self:updateNonBatterRunners(C.WalkedRunnerSpeed, true) then + if not self:updateNonBatterRunners(C.WalkedRunnerSpeed, true, true) then self.state.offenseState = C.Offense.batting end elseif self.state.offenseState == C.Offense.homeRun then - self:updateNonBatterRunners(C.WalkedRunnerSpeed * 2, false) + self:updateNonBatterRunners(C.WalkedRunnerSpeed * 2, false, true) if #self.baserunning.runners == 0 then -- Give the player a moment to enjoy their home run. playdate.timer.new(1500, function() @@ -607,8 +626,12 @@ function Game:update() local ballHeldBy for _, fielder in pairs(self.fielding.fielders) do addDraw(fielder.y + danceOffset, function() - local ballHeldByThisFielder = - drawFielder(self.state.fieldingTeamSprites[fielder.spriteIndex], self.state.ball, fielder.x, fielder.y + danceOffset) + local ballHeldByThisFielder = drawFielder( + self.state.fieldingTeamSprites[fielder.spriteIndex], + self.state.ball, + fielder.x, + fielder.y + danceOffset + ) if ballHeldByThisFielder then ballHeldBy = fielder end @@ -622,7 +645,10 @@ function Game:update() if self.state.batAngleDeg > 50 and self.state.batAngleDeg < 200 then self.state.battingTeamSprites[runner.spriteIndex].back:draw(runner.x, runner.y - playerHeightOffset) else - self.state.battingTeamSprites[runner.spriteIndex].smiling:draw(runner.x, runner.y - playerHeightOffset) + self.state.battingTeamSprites[runner.spriteIndex].smiling:draw( + runner.x, + runner.y - playerHeightOffset + ) end else -- TODO? Change blip speed depending on runner speed? @@ -650,7 +676,7 @@ function Game:update() self.state.battingTeamSprites[runner.spriteIndex].smiling:draw(runner.x, runner.y - playerHeightOffset) end - if self:userIsOn('defense') then + if self:userIsOn("defense") then throwMeter:drawNearFielder(ballHeldBy) end diff --git a/src/pitching.lua b/src/pitching.lua index 5983465..42381a3 100644 --- a/src/pitching.lua +++ b/src/pitching.lua @@ -21,21 +21,36 @@ Pitches = { -- Fastball function(accuracy) return { - x = gfx.animator.new(0, C.PitchStart.x, getPitchMissBy(accuracy) + 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), } end, -- Curve ball function(accuracy) return { - x = gfx.animator.new(C.PitchFlyMs, getPitchMissBy(accuracy) + 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), } end, -- Slider function(accuracy) return { - x = gfx.animator.new(C.PitchFlyMs, getPitchMissBy(accuracy) + 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), } end, @@ -44,10 +59,11 @@ Pitches = { return { x = { currentValue = function() - return getPitchMissBy(accuracy) + C.PitchStart.x + (10 * math.sin((ball.yAnimator:currentValue() - C.PitchStart.y) / 10)) - end, - reset = function() + return getPitchMissBy(accuracy) + + C.PitchStart.x + + (10 * math.sin((ball.yAnimator:currentValue() - C.PitchStart.y) / 10)) end, + reset = function() end, }, y = gfx.animator.new(C.PitchFlyMs * 1.3, C.PitchStart.y, C.PitchEndY, playdate.easingFunctions.linear), }