local gfx = playdate.graphics local HeaderFont = Roobert11Medium local DetailFont = FontFullCircle ---@alias TextObject { text: string, font: pd_font } ---@param texts TextObject[] local function drawTexts(texts) local xOffset = 10 local initialOffset = -(HeaderFont:getHeight()) / 2 local yOffset = initialOffset --- The text height plus a margin scaled to that height function getOffsetOffset(textObject) return (-4 + math.floor(textObject.font:getHeight() * 1.6)) / 2 end -- Inverted buffer around text to separate it from the background for _, textObject in ipairs(texts) do local offsetOffset = getOffsetOffset(textObject) yOffset = yOffset + offsetOffset gfx.setImageDrawMode(gfx.kDrawModeInverted) for x = xOffset - 6, xOffset + 6 do for y = yOffset - 6, yOffset + 6 do textObject.font:drawText(textObject.text, x, y) end end yOffset = yOffset + offsetOffset end -- Drawing the actual text afterward (instead of inline) keeps the inverted buffer from drawing over it. yOffset = initialOffset gfx.setImageDrawMode(gfx.kDrawModeCopy) for _, textObject in ipairs(texts) do local offsetOffset = getOffsetOffset(textObject) yOffset = yOffset + offsetOffset textObject.font:drawText(textObject.text, xOffset, yOffset) yOffset = yOffset + offsetOffset end end ---@param text string ---@return TextObject local function header(text) return { text = text, font = HeaderFont } end ---@param text string ---@return TextObject local function detail(text) return { text = text, font = DetailFont } end ---@class ControlScreen ---@field sceneToReturnTo Scene ---@field private renderedImage pd_image Static image doesn't need to be constantly re-rendered. ControlScreen = {} ---@return pd_image local function draw() local image = gfx.image.new(C.Screen.W, C.Screen.H) gfx.pushContext(image) BallBackground:draw(0, 0) drawTexts({ header("Batting:"), detail("Swing the crank to swing your bat"), detail("But watch out! Some pitches are tricky!"), header("Pitching:"), detail("Swing the crank to pitch the ball"), detail("But be careful! Throw too hard and it might go wild!"), detail("(shh: try holding A or B while you pitch)"), header("Fielding:"), detail("To throw, hold a direction button and crank!"), detail("Right throws to 1st, Up goes to 2nd, etc."), }) gfx.popContext() return image end ---@param sceneToReturnTo Scene ---@return ControlScreen function ControlScreen.new(sceneToReturnTo) return setmetatable({ sceneToReturnTo = sceneToReturnTo, renderedImage = draw(), }, { __index = ControlScreen }) end function ControlScreen:update() gfx.animation.blinker.updateAll() gfx.clear() self.renderedImage:draw(0, 0) drawButton("B", 370, 210) if playdate.buttonJustPressed(playdate.kButtonA) or playdate.buttonJustPressed(playdate.kButtonB) then transitionBetween(self, self.sceneToReturnTo) end end