Files
behind_glass/src/input/GyroController.ts
T
2026-10-06 12:16:46 +09:00

30 lines
2.2 KiB
TypeScript

export class GyroController {
private enabled = false;
private pending = false;
private generation = 0;
private hasReading = false;
private base: { beta: number; gamma: number } | null = null;
constructor(private readonly setView: (x: number, y: number) => void, private readonly status: (message: string) => void) {}
async toggle(): Promise<boolean> {
if (this.enabled || this.pending) { this.dispose(); return false; }
if (!window.isSecureContext || !('DeviceOrientationEvent' in window)) { this.status('자이로스코프를 사용할 수 없습니다.'); return false; }
const generation = ++this.generation; this.pending = true;
try {
const device = window.DeviceOrientationEvent as typeof DeviceOrientationEvent & { requestPermission?: () => Promise<string> };
this.status('센서 권한을 기다리는 중…');
if (device.requestPermission && await device.requestPermission() !== 'granted') throw new Error('권한 거절됨');
if (generation !== this.generation) return false;
this.base = null; this.hasReading = false; this.pending = false; this.enabled = true; window.addEventListener('deviceorientation', this.onOrientation); this.status('센서값을 기다리는 중…'); return true;
} catch (error) { this.pending = false; if (generation === this.generation) this.status(`자이로스코프를 사용할 수 없습니다 (${(error as Error).message})`); return false; }
}
reset(): void { this.base = null; }
dispose(): void { ++this.generation; this.pending = false; this.enabled = false; this.base = null; window.removeEventListener('deviceorientation', this.onOrientation); }
private onOrientation = (event: DeviceOrientationEvent): void => {
if (!this.enabled || event.beta == null || event.gamma == null) return;
if (!this.base) this.base = { beta: event.beta, gamma: event.gamma };
const angle = (screen.orientation?.angle ?? 0) * Math.PI / 180;
const x = event.gamma - this.base.gamma; const y = event.beta - this.base.beta;
this.setView((x * Math.cos(angle) + y * Math.sin(angle)) / 35, (y * Math.cos(angle) - x * Math.sin(angle)) / 35); if (!this.hasReading) { this.hasReading = true; this.status('자이로스코프 활성'); }
};
}