local World = require("game.world") local Camera = { x = 2000, y = 900, zoom = 0.35, } local MAX_ZOOM = 3.5 local MIN_ZOOM = 0.3 local ZOOM_SPEED = 2.0 function Camera.update(lander, terrain, dt) -- Track lander X Camera.x = lander.x -- Get ground height below lander local groundY = terrain.getHeightAt(lander.x) local altitude = groundY - lander.y -- Camera Y: keep terrain in the lower portion of the viewport even at high altitude local targetY = lander.y + altitude * 0.45 Camera.y = Camera.y + (targetY - Camera.y) * math.min(1, dt * 3) -- Zoom: fit the distance from lander to ground within the viewport -- We want the full altitude span to fit in about 70% of screen height local sw, sh = World.screenW, World.screenH local effectiveScale = World.baseScale local neededHeight = math.max(altitude + 100, 200) -- minimum view range local viewportFraction = 0.7 local targetZoom = (sh * viewportFraction) / (neededHeight * effectiveScale) targetZoom = math.max(MIN_ZOOM, math.min(MAX_ZOOM, targetZoom)) Camera.zoom = Camera.zoom + (targetZoom - Camera.zoom) * math.min(1, dt * ZOOM_SPEED) end function Camera.getAltitude(landerY, terrain, landerX) local groundY = terrain.getHeightAt(landerX) return math.max(0, groundY - landerY) end function Camera.applyTransform() local sw, sh = World.screenW, World.screenH local scale = World.baseScale * Camera.zoom love.graphics.push() love.graphics.translate(sw / 2, sh / 2) love.graphics.scale(scale) love.graphics.translate(-Camera.x, -Camera.y) end function Camera.popTransform() love.graphics.pop() end function Camera.getVisibleRect() local sw, sh = World.screenW, World.screenH local scale = World.baseScale * Camera.zoom local hw = (sw / 2) / scale local hh = (sh / 2) / scale return Camera.x - hw, Camera.y - hh, Camera.x + hw, Camera.y + hh end function Camera.getZoom() return Camera.zoom end function Camera.reset() Camera.x = 2000 Camera.y = 900 Camera.zoom = MIN_ZOOM end return Camera