BatterUp/src/announcer.lua

72 lines
2.3 KiB
Lua

-- selene: allow(shadowing)
local gfx = playdate.graphics
local AnnouncementFont <const> = playdate.graphics.font.new("fonts/Roobert-20-Medium.pft")
local AnnouncementTransitionMs <const> = 300
local AnnouncerMarginX <const> = 26
local AnnouncerAnimatorInY <const> =
playdate.graphics.animator.new(AnnouncementTransitionMs, -70, 0, playdate.easingFunctions.outBounce)
local AnnouncerAnimatorOutY <const> =
playdate.graphics.animator.new(AnnouncementTransitionMs, 0, -70, playdate.easingFunctions.outQuint)
-- selene: allow(unscoped_variables)
---@class Announcer
---@field textQueue string[]
---@field animatorY pd_animator
Announcer = {}
function Announcer.new()
return setmetatable({
textQueue = {},
animatorY = AnnouncerAnimatorInY,
}, { __index = Announcer })
end
local DurationMs <const> = 2000
function Announcer:popIn()
self.animatorY = AnnouncerAnimatorInY
self.animatorY:reset()
playdate.timer.new(DurationMs, function()
self.animatorY = AnnouncerAnimatorOutY
self.animatorY:reset()
-- If this popIn() call was inside a timer, successive messages would be
-- allowed to transition out. However, the Out animation, shortly followed by
-- a new message popping in, is actually *more* jarring than the interrupt.
if #self.textQueue ~= 1 then
self:popIn()
table.remove(self.textQueue, 1)
else
playdate.timer.new(AnnouncementTransitionMs, function()
table.remove(self.textQueue, 1)
end)
end
end)
end
function Announcer:say(text)
self.textQueue[#self.textQueue + 1] = text
if #self.textQueue == 1 then
self:popIn()
end
end
function Announcer:draw(x, y)
if #self.textQueue == 0 then
return
end
x = x - 5 -- Infield center is slightly offset from screen center
local originalDrawMode = gfx.getImageDrawMode()
local width = math.max(150, (AnnouncerMarginX * 2) + AnnouncementFont:getTextWidth(self.textQueue[1]))
local animY = self.animatorY:currentValue()
gfx.setColor(gfx.kColorBlack)
gfx.fillRect(x - (width / 2), y + animY, width, 50)
gfx.setImageDrawMode(gfx.kDrawModeInverted)
AnnouncementFont:drawTextAligned(self.textQueue[1], x, y + 10 + animY, kTextAlignment.center)
gfx.setImageDrawMode(originalDrawMode)
end