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