Initial commit: Retro 90s flight simulator MVP
Loading screen, main menu, 3D flight sim with CRT post-processing, procedural terrain, airport with buildings, low-poly aircraft, flight physics, HUD instruments, and sound. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+77
@@ -0,0 +1,77 @@
|
||||
export class Sound {
|
||||
constructor() {
|
||||
this.ctx = null;
|
||||
this.engineOsc = null;
|
||||
this.engineGain = null;
|
||||
this.initialized = false;
|
||||
}
|
||||
|
||||
init() {
|
||||
if (this.initialized) return;
|
||||
try {
|
||||
this.ctx = new (window.AudioContext || window.webkitAudioContext)();
|
||||
this.engineOsc = this.ctx.createOscillator();
|
||||
this.engineOsc.type = 'sawtooth';
|
||||
this.engineGain = this.ctx.createGain();
|
||||
this.engineGain.gain.value = 0;
|
||||
|
||||
// Low-pass filter for muffled engine sound
|
||||
this.engineFilter = this.ctx.createBiquadFilter();
|
||||
this.engineFilter.type = 'lowpass';
|
||||
this.engineFilter.frequency.value = 300;
|
||||
|
||||
this.engineOsc.connect(this.engineFilter);
|
||||
this.engineFilter.connect(this.engineGain);
|
||||
this.engineGain.connect(this.ctx.destination);
|
||||
this.engineOsc.start();
|
||||
this.initialized = true;
|
||||
} catch {
|
||||
// Audio not available, silently fail
|
||||
}
|
||||
}
|
||||
|
||||
update(throttle) {
|
||||
if (!this.initialized || !this.engineOsc) return;
|
||||
const baseFreq = 60;
|
||||
const maxFreq = 180;
|
||||
this.engineOsc.frequency.value = baseFreq + throttle * (maxFreq - baseFreq);
|
||||
this.engineGain.gain.value = Math.min(throttle * 0.08, 0.08);
|
||||
this.engineFilter.frequency.value = 200 + throttle * 200;
|
||||
}
|
||||
|
||||
beep(frequency = 800, duration = 80) {
|
||||
if (!this.initialized) return;
|
||||
try {
|
||||
const osc = this.ctx.createOscillator();
|
||||
const gain = this.ctx.createGain();
|
||||
osc.type = 'square';
|
||||
osc.frequency.value = frequency;
|
||||
gain.gain.value = 0.05;
|
||||
osc.connect(gain);
|
||||
gain.connect(this.ctx.destination);
|
||||
osc.start();
|
||||
osc.stop(this.ctx.currentTime + duration / 1000);
|
||||
} catch {
|
||||
// Ignore audio errors
|
||||
}
|
||||
}
|
||||
|
||||
takeoffSound() {
|
||||
if (!this.initialized) return;
|
||||
try {
|
||||
const osc = this.ctx.createOscillator();
|
||||
const gain = this.ctx.createGain();
|
||||
osc.type = 'triangle';
|
||||
osc.frequency.value = 400;
|
||||
osc.frequency.linearRampToValueAtTime(800, this.ctx.currentTime + 0.3);
|
||||
gain.gain.value = 0.08;
|
||||
gain.gain.linearRampToValueAtTime(0, this.ctx.currentTime + 0.5);
|
||||
osc.connect(gain);
|
||||
gain.connect(this.ctx.destination);
|
||||
osc.start();
|
||||
osc.stop(this.ctx.currentTime + 0.5);
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user