Refactoring.

Consolidate hitBall() and throwBall() into one function.
Pull playerImage into its own "blipper" in utils.lua. This is definitely overkill, but we're learning with Lua, and it's fine, and it's very fine.
This commit is contained in:
Sage Vaillancourt 2025-01-27 00:26:20 -05:00
parent 8bbc029c42
commit 2c179a5ba5
2 changed files with 53 additions and 37 deletions

View File

@ -1,3 +1,4 @@
import 'CoreLibs/animation.lua'
import 'CoreLibs/animator.lua' import 'CoreLibs/animator.lua'
import 'CoreLibs/easing.lua' import 'CoreLibs/easing.lua'
import 'CoreLibs/graphics.lua' import 'CoreLibs/graphics.lua'
@ -11,11 +12,12 @@ gfx.setBackgroundColor(gfx.kColorWhite)
playdate.setMenuImage(gfx.image.new("images/game/menu-image.png")) playdate.setMenuImage(gfx.image.new("images/game/menu-image.png"))
local grassBackground = gfx.image.new("images/game/grass.png") local grassBackground = gfx.image.new("images/game/grass.png")
local playerHighHat = gfx.image.new("images/game/player.png")
local playerLowHat = gfx.image.new("images/game/player-lowhat.png") local playerImageBlipper = blipper.new(
local playerImage = playerHighHat 100,
local secPerFrame = 0.1 "images/game/player.png",
local playerFrameElapsed = 0 "images/game/player-lowhat.png"
)
local backgroundPan = { local backgroundPan = {
x = 0, x = 0,
@ -64,8 +66,13 @@ local bases = {
home = { x = screenW * 0.474, y = screenH * 0.79 } home = { x = screenW * 0.474, y = screenH * 0.79 }
} }
local fielderSpeed = 40
local fielders = { local fielders = {
first = {}, first = {
x = nil,
y = nil,
covering = nil -- TODO?
},
second = {}, second = {},
shortstop = {}, shortstop = {},
third = {}, third = {},
@ -100,17 +107,13 @@ local player = {
local runners = { } local runners = { }
function hitBall(destX, destY, hitFlyTime) function throwBall(destX, destY, easingFunc, flyTimeMs)
ballSizeAnimator:reset(ballSizeMs) if not flyTimeMs then
hitAnimatorY = gfx.animator.new(hitFlyTime, ballY, destY, playdate.easingFunctions.outQuint) flyTimeMs = distanceBetween(ballX, ballY, destX, destY) * 5
hitAnimatorX = gfx.animator.new(hitFlyTime, ballX, destX, playdate.easingFunctions.outQuint) end
end ballSizeAnimator:reset(flyTimeMs)
hitAnimatorY = gfx.animator.new(flyTimeMs, ballY, destY, easingFunc)
function throwBall(destX, destY) hitAnimatorX = gfx.animator.new(flyTimeMs, ballX, destX, easingFunc)
local throwFlyTime = distanceBetween(ballX, ballY, destX, destY) * 5
ballSizeAnimator:reset(throwFlyTime)
hitAnimatorY = gfx.animator.new(throwFlyTime, ballY, destY, playdate.easingFunctions.linear)
hitAnimatorX = gfx.animator.new(throwFlyTime, ballX, destX, playdate.easingFunctions.linear)
end end
function pitch() function pitch()
@ -159,8 +162,7 @@ function updateInfield()
return return
end end
local fielderSpeed = 40 for _,fielder in pairs(fielders) do
for title,fielder in pairs(fielders) do
if fielder.targetX ~= nil and fielder.targetY ~= nil then if fielder.targetX ~= nil and fielder.targetY ~= nil then
local x, y, distance = normalizeVector(fielder.x, fielder.y, fielder.targetX, fielder.targetY) local x, y, distance = normalizeVector(fielder.x, fielder.y, fielder.targetX, fielder.targetY)
@ -266,6 +268,7 @@ function updateGameState()
crankChange, acceleratedChange = playdate.getCrankChange() crankChange, acceleratedChange = playdate.getCrankChange()
if currentMode == MODES.batting and acceleratedChange >= 0 and if currentMode == MODES.batting and acceleratedChange >= 0 and
pointDirectlyUnderLine(ballX, ballY, batBaseX, batBaseY, batTipX, batTipY, screenH) then pointDirectlyUnderLine(ballX, ballY, batBaseX, batBaseY, batTipX, batTipY, screenH) then
currentMode = MODES.running
ballAngle = batAngle + math.rad(90) ballAngle = batAngle + math.rad(90)
mult = math.abs(acceleratedChange / 15) mult = math.abs(acceleratedChange / 15)
@ -277,17 +280,17 @@ function updateGameState()
end end
ballDestX = ballX + (ballVelX * hitMult) ballDestX = ballX + (ballVelX * hitMult)
ballDestY = ballY + (ballVelY * hitMult) ballDestY = ballY + (ballVelY * hitMult)
hitBall(ballDestX, ballDestY, 2000) throwBall(ballDestX, ballDestY, playdate.easingFunctions.outQuint, 2000)
local chasingFielder = getNearestFielder(ballDestX, ballDestY) local chasingFielder = getNearestFielder(ballDestX, ballDestY)
chasingFielder.targetX = ballDestX chasingFielder.targetX = ballDestX
chasingFielder.targetY = ballDestY chasingFielder.targetY = ballDestY
chasingFielder.onArrive = function() chasingFielder.onArrive = function()
throwBall(getNextThrowTarget()) local targetX, targetY = getNextThrowTarget()
throwBall(targetX, targetY, playdate.easingFunctions.linear)
chasingFielder.onArrive = nil chasingFielder.onArrive = nil
end end
fielders.first.targetX = bases.first.x fielders.first.targetX = bases.first.x
fielders.first.targetY = bases.first.y fielders.first.targetY = bases.first.y
currentMode = MODES.running
player.nextBase = bases.first player.nextBase = bases.first
runners[#runners+1] = player runners[#runners+1] = player
end end
@ -316,6 +319,7 @@ end
function playdate.update() function playdate.update()
updateGameState() updateGameState()
playdate.graphics.animation.blinker.updateAll()
gfx.clear() gfx.clear()
grassBackground:draw(backgroundPan.x - 400, backgroundPan.y - 240) grassBackground:draw(backgroundPan.x - 400, backgroundPan.y - 240)
@ -324,7 +328,7 @@ function playdate.update()
gfx.setLineWidth(2) gfx.setLineWidth(2)
gfx.drawCircleAtPoint(ballX + backgroundPan.x, ballY + backgroundPan.y, ballSize) gfx.drawCircleAtPoint(ballX + backgroundPan.x, ballY + backgroundPan.y, ballSize)
for title,fielder in pairs(fielders) do for _,fielder in pairs(fielders) do
gfx.fillRect(fielder.x + backgroundPan.x, fielder.y + backgroundPan.y, 14, 25) gfx.fillRect(fielder.x + backgroundPan.x, fielder.y + backgroundPan.y, 14, 25)
end end
@ -337,23 +341,15 @@ function playdate.update()
) )
end end
if playdate.isCrankDocked() then if playdate.isCrankDocked() or (crankChange < 2 and currentMode == MODES.running) then
playdate.ui.crankIndicator:draw() playdate.ui.crankIndicator:draw()
end end
playerImage:draw(player.x + backgroundPan.x, player.y + backgroundPan.y) playerImageBlipper:draw(
currentMode ~= MODES.running,
-- TODO: Use gfx.animation.blinker instead player.x + backgroundPan.x,
if currentMode == MODES.running and playerFrameElapsed > secPerFrame then player.y + backgroundPan.y
playerFrameElapsed = 0 )
if playerImage == playerHighHat then
playerImage = playerLowHat
else
playerImage = playerHighHat
end
else
playerFrameElapsed += deltaTime
end
-- for i,runner in pairs(runners) do -- for i,runner in pairs(runners) do
-- playerImage:draw(runner.x, runner.y) -- playerImage:draw(runner.x, runner.y)

View File

@ -1,3 +1,6 @@
import 'CoreLibs/animation.lua'
import 'CoreLibs/graphics.lua'
--- Returns the normalized vector as two values, plus the distance between the given points. --- Returns the normalized vector as two values, plus the distance between the given points.
function normalizeVector(x1, y1, x2, y2) function normalizeVector(x1, y1, x2, y2)
local distance, a, b = distanceBetween(x1, y1, x2, y2) local distance, a, b = distanceBetween(x1, y1, x2, y2)
@ -29,3 +32,20 @@ function pointDirectlyUnderLine(pointX, pointY, lineX1, lineY1, lineX2, lineY2,
return yDelta <= 0 return yDelta <= 0
end end
blipper = {
--- Build an object that simply "blips" between the given images at the given interval.
--- Expects `playdate.graphics.animation.blinker.updateAll()` to be called on every update.
new = function(msInterval, imagePath1, imagePath2)
local blinker = playdate.graphics.animation.blinker.new(msInterval, msInterval, true)
blinker:start()
return {
blinker = blinker,
image1 = playdate.graphics.image.new(imagePath1),
image2 = playdate.graphics.image.new(imagePath2),
draw = function(self, disableBlipping, x, y)
local currentImage = (disableBlipping or self.blinker.on) and self.image2 or self.image1
currentImage:draw(x, y)
end
}
end
}