local gfx = love.graphics --- ---@generic T ---@param shape T | fun() ---@param process fun(entity: T, dt: number, system: System) | nil ---@return System | { entities: T[] } local function drawSystem(name, shape, process) local system = filteredSystem(name, shape, process, function(_, a, b) if a.z ~= nil and b.z ~= nil then return a.z < b.z end if a.z ~= nil then return true end return false end) system.isDrawSystem = true return system end filteredSystem("mapGridPositionToRealPosition", { gridPosition = T.XyPair }, function(e, dt, system) local target = PositionAtGridXy(e.gridPosition.x, e.gridPosition.y) if e.position == nil then e.position = target return end local speed = 100 if e.ballEffects and e.ballEffects.movement then local movement = e.ballEffects.movement local longTarget = PositionAtGridXy(e.gridPosition.x + movement.x, e.gridPosition.y + movement.y) local xDiff = e.position.x - longTarget.x local yDiff = e.position.y - longTarget.y speed = 30 + math.sqrt((xDiff * xDiff) + (yDiff * yDiff)) end local stops = 0 local xDiff = target.x - e.position.x local xChange = dt * speed * math.sign(xDiff) if math.abs(xDiff) <= math.abs(xChange) then e.position.x = target.x stops = stops + 1 else e.position.x = e.position.x + xChange end local yDiff = target.y - e.position.y local yChange = dt * speed * math.sign(yDiff) if math.abs(yDiff) <= math.abs(yChange) then e.position.y = target.y stops = stops + 1 else e.position.y = e.position.y + yChange end if e.endAnimating and stops == 2 then RoundSystem:remove("animating") end system.world:addEntity(e) end) local spriteDrawSystem = drawSystem( "drawSprites", { position = T.XyPair, drawAsSprite = T.Drawable, rotation = Maybe(T.number) }, function(e) if not e.drawAsSprite then return end gfx.draw(e.drawAsSprite, e.position.x, e.position.y) end ) function spriteDrawSystem:preProcess() gfx.setColor(1, 1, 1) end local margin = 8 drawSystem( "drawText", { position = T.XyPair, drawAsText = { text = T.str, style = Maybe(T.str), font = Maybe(T.pd_font) } }, function(e) local font = e.drawAsText.font or gfx.getFont() -- e.drawAsText.font or AshevilleSans14Bold local textHeight = font:getHeight() local textWidth = font:getWidth(e.drawAsText.text) local bgLeftEdge = e.position.x - margin -- - (textWidth / 2) local bgTopEdge = e.position.y - 2 local bgWidth, bgHeight = textWidth + (margin * 2), textHeight + 2 if e.drawAsText.style == TextStyle.Inverted then gfx.setColor(0, 0, 0) gfx.rectangle("fill", bgLeftEdge, bgTopEdge, textWidth + margin, textHeight + 2) gfx.setColor(1, 1, 1) elseif e.drawAsText.style == TextStyle.Bordered then gfx.setColor(1, 1, 1) gfx.rectangle("fill", bgLeftEdge, bgTopEdge, bgWidth, bgHeight) gfx.setColor(0, 0, 0) gfx.rectangle("line", bgLeftEdge, bgTopEdge, bgWidth, bgHeight) end gfx.print(e.drawAsText.text, bgLeftEdge + margin, bgTopEdge + margin) end ) drawSystem("drawRectangles", { position = T.XyPair, drawAsRectangle = { size = T.XyPair } }, function(e, _, _) gfx.setColor(1, 1, 1, 0.5) local mode = e.drawAsRectangle.mode or "line" -- (e.highlighted and "fill" or "line") gfx.rectangle(mode, e.position.x, e.position.y, e.drawAsRectangle.size.x, e.drawAsRectangle.size.y) end)