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