summaryrefslogtreecommitdiff
path: root/camera.lua
diff options
context:
space:
mode:
authorcursed22bc <admin@pixeldawn.org>2026-02-27 13:37:36 +0200
committercursed22bc <admin@pixeldawn.org>2026-02-27 13:37:36 +0200
commitf8da1a788c68ff58d53a173ad197ef3623dc6cff (patch)
tree63d417cac1782968a556675acbc8a506504d9069 /camera.lua
parentc528c8fa70a1399efc746be6468bd7d36abe1ca2 (diff)
base setup
Diffstat (limited to 'camera.lua')
-rw-r--r--camera.lua118
1 files changed, 118 insertions, 0 deletions
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