// FILE: lib/game/Camera.ts import { lerp } from "../utils"; interface Target { x: number; y: number; width: number; height: number; } export class Camera { // Current camera properties x: number; y: number; zoom: number = 1; // Target properties for smooth transitions private targetX: number; private targetY: number; private targetZoom: number = 1; private followTarget: Target | null = null; // Smoothing factor for lerping private readonly LERP_FACTOR = 0.08; constructor(canvasWidth: number, canvasHeight: number) { this.x = canvasWidth / 2; this.y = canvasHeight / 2; this.targetX = this.x; this.targetY = this.y; } // --- Public methods for the sandbox API --- panTo(x: number, y: number) { this.followTarget = null; // Stop following any target when manually panning this.targetX = x; this.targetY = y; } setZoom(level: number) { this.targetZoom = Math.max(0.5, Math.min(level, 3)); // Clamp zoom level } focusOn(target: Target) { this.followTarget = target; } reset() { this.followTarget = null; this.targetX = 0; // Or initial canvas center this.targetY = 0; // Or initial canvas center this.targetZoom = 1; } // --- Internal update method for the game loop --- update() { if (this.followTarget) { this.targetX = this.followTarget.x + this.followTarget.width / 2; this.targetY = this.followTarget.y + this.followTarget.height / 2; } // Smoothly interpolate current values towards target values this.x = lerp(this.x, this.targetX, this.LERP_FACTOR); this.y = lerp(this.y, this.targetY, this.LERP_FACTOR); this.zoom = lerp(this.zoom, this.targetZoom, this.LERP_FACTOR); } // --- Method to apply transformations to the canvas context --- public applyTransform(ctx: CanvasRenderingContext2D, shake: { offsetX: number, offsetY: number }) { const canvasWidth = ctx.canvas.width; const canvasHeight = ctx.canvas.height; // First, move the canvas origin to the center of the screen ctx.translate(canvasWidth / 2, canvasHeight / 2); // Then, apply the zoom ctx.scale(this.zoom, this.zoom); // Finally, pan the camera to the target coordinates ctx.translate(-this.x, -this.y); // NEW: Apply the camera shake as the very last translation ctx.translate(shake.offsetX, shake.offsetY); } }