Spaces:
Paused
Paused
| // 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); | |
| } | |
| } |