From f8da1a788c68ff58d53a173ad197ef3623dc6cff Mon Sep 17 00:00:00 2001 From: cursed22bc Date: Fri, 27 Feb 2026 13:37:36 +0200 Subject: base setup --- camera.lua | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 camera.lua (limited to 'camera.lua') diff --git a/camera.lua b/camera.lua new file mode 100644 index 0000000..752b32e --- /dev/null +++ b/camera.lua @@ -0,0 +1,118 @@ +local Camera = {} +Camera.__index = Camera + +function Camera:new(target, width, height, mouseFollow, screenToWorldScale) + local self = setmetatable({}, Camera) + self.target = target + self.width = width + self.height = height + self.mouseFollow = mouseFollow or false + self.mouseRadius = math.min(self.width, self.height) * 0.35 + self.mouseWeight = 0.1 + self.screenToWorldScale = screenToWorldScale + + self.x = target.x + (target.width) / 2 - self.width / 2 + self.y = target.y + (target.height) / 2 - self.height / 2 + + self.vx = 0 + self.vy = 0 + + self.stiffness = 50 + self.damping = 2 * math.sqrt(self.stiffness) + + self.limits = { + maxX = nil, + minX = nil, + maxY = nil, + minY = nil, + } + + return self +end + +function Camera:setTarget(target) + self.target = target +end + +function Camera:setLimits(minX, maxX, minY, maxY) + self.limits.minX = minX + self.limits.maxX = maxX + self.limits.minY = minY + self.limits.maxY = maxY +end + +function Camera:update(dt) + if not self.target then return end + local cx = self.target.x + (self.target.width or 0) / 2 + local cy = self.target.y + (self.target.height or 0) / 2 + local targetX = cx - self.width / 2 + local targetY = cy - self.height / 2 + + if self.mouseFollow then + local sw = love.graphics.getWidth() + local sh = love.graphics.getHeight() + local mx, my = love.mouse.getPosition() + + local offsetX = (mx - sw / 2) * self.screenToWorldScale + local offsetY = (my - sh / 2) * self.screenToWorldScale + + local dist = offsetX * offsetX + offsetY * offsetY + if dist > self.mouseRadius * self.mouseRadius then + local inv = self.mouseRadius / math.sqrt(dist) + offsetX = offsetX * inv + offsetY = offsetY * inv + end + + targetX = targetX + offsetX * self.mouseWeight + targetY = targetY + offsetY * self.mouseWeight + end + + local accelerationX = (targetX - self.x) * self.stiffness - self.vx * self.damping + local accelerationY = (targetY - self.y) * self.stiffness - self.vy * self.damping + + self.vx = self.vx + accelerationX * dt + self.vy = self.vy + accelerationY * dt + + self.x = self.x + self.vx * dt + self.y = self.y + self.vy * dt + + local lim = self.limits + if lim.minX ~= nil then self.x = math.max(lim.minX, self.x) end + if lim.maxX ~= nil then self.x = math.min(self.x, lim.maxX - self.width) end + if lim.minY ~= nil then self.y = math.max(lim.minY, self.y) end + if lim.maxY ~= nil then self.y = math.min(self.y, lim.maxY - self.height) end +end + +function Camera:set(padding) + padding = padding or 0 + love.graphics.push() + + local canvasW = love.graphics.getCanvas():getWidth() + local canvasH = love.graphics.getCanvas():getHeight() + + local viewW = self.width + padding * 2 + local viewH = self.height + padding * 2 + + local scaleX = canvasW / viewW + local scaleY = canvasH / viewH + + local scale = math.floor(math.min(scaleX, scaleY)) + + love.graphics.scale(scale) + + local snapX = math.floor(self.x) + local snapY = math.floor(self.y) + love.graphics.translate(-(snapX - padding), -(snapY - padding)) +end + +function Camera:unset() + love.graphics.pop() +end + +function Camera:getSubPixelOffset() + local dx = self.x - math.floor(self.x) + local dy = self.y - math.floor(self.y) + return dx, dy +end + +return Camera \ No newline at end of file -- cgit v1.2.3