import * as THREE from "three"; /** * 响应式视口管理器。 * * 监听 container resize(通过 ResizeObserver),自动更新: * - renderer 尺寸与像素比 * - camera 宽高比 * * 比 Phaser 的 reload 方案更高效,无需刷新页面。 */ export class ViewportManager { private renderer: THREE.WebGLRenderer; private camera: THREE.PerspectiveCamera; private container: HTMLElement; private observer: ResizeObserver | null = null; private maxPixelRatio: number; constructor( renderer: THREE.WebGLRenderer, camera: THREE.PerspectiveCamera, container: HTMLElement, maxPixelRatio = 2, ) { this.renderer = renderer; this.camera = camera; this.container = container; this.maxPixelRatio = maxPixelRatio; } enable(): void { this.observer = new ResizeObserver(() => this.handleResize()); this.observer.observe(this.container); } disable(): void { this.observer?.disconnect(); this.observer = null; } /** 手动触发一次 resize 计算 */ refresh(): void { this.handleResize(); } getSize(): { width: number; height: number; aspect: number } { const width = this.container.clientWidth; const height = this.container.clientHeight; return { width, height, aspect: width / height }; } private handleResize(): void { const { width, height, aspect } = this.getSize(); if (width === 0 || height === 0) return; this.camera.aspect = aspect; this.camera.updateProjectionMatrix(); this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, this.maxPixelRatio)); this.renderer.setSize(width, height); } }