From 2c179a5ba52697b8074129936a3f73a4f77d5c42 Mon Sep 17 00:00:00 2001 From: Sage Vaillancourt Date: Mon, 27 Jan 2025 00:26:20 -0500 Subject: [PATCH] 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. --- src/main.lua | 70 ++++++++++++++++++++++++--------------------------- src/utils.lua | 20 +++++++++++++++ 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/src/main.lua b/src/main.lua index 76d42e1..f901b93 100644 --- a/src/main.lua +++ b/src/main.lua @@ -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) -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) +function throwBall(destX, destY, easingFunc, flyTimeMs) + if not flyTimeMs then + flyTimeMs = distanceBetween(ballX, ballY, destX, destY) * 5 + end + 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) diff --git a/src/utils.lua b/src/utils.lua index f53fff3..86820e8 100644 --- a/src/utils.lua +++ b/src/utils.lua @@ -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 +} \ No newline at end of file