From f56e26a9b48b7126a3514d9bf856cdbe660859d7 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Thu, 18 Sep 2025 14:33:53 +0200 Subject: [PATCH] =?UTF-8?q?=C3=84nderung:=20Verbesserung=20der=20Audio-Int?= =?UTF-8?q?egration=20und=20Steuerung=20im=20Taxi-Spiel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Änderungen: - Hinzufügung einer motorStopTimeout-Logik zur verzögerten Stopp-Funktion des Motorgeräuschs, um eine realistischere Audio-Steuerung zu ermöglichen. - Übernahme eines globalen AudioContext und MotorSound, um die Wiederverwendbarkeit zu verbessern und die Initialisierung zu optimieren. - Anpassung der Logik zur Audio-Initialisierung und -Steuerung, um die Benutzererfahrung zu verbessern. Diese Anpassungen optimieren die Audio-Performance und die Interaktion im Taxi-Minispiel erheblich. --- frontend/src/views/minigames/TaxiGame.vue | 71 +++++++++++++++++------ 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/frontend/src/views/minigames/TaxiGame.vue b/frontend/src/views/minigames/TaxiGame.vue index 986e273..282eb42 100644 --- a/frontend/src/views/minigames/TaxiGame.vue +++ b/frontend/src/views/minigames/TaxiGame.vue @@ -247,6 +247,7 @@ export default { audioContext: null, audioUnlockHandler: null, selectedStreetName: null + ,motorStopTimeout: null ,houseNumbers: {} } }, @@ -488,7 +489,13 @@ export default { if (this.audioContext) return; // Bereits initialisiert try { - this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); + // Übernehme ggf. global vorhandenen Context + if (window.__TaxiAudioContext) { + this.audioContext = window.__TaxiAudioContext; + } else { + this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); + window.__TaxiAudioContext = this.audioContext; + } if (import.meta.env?.DEV) console.log('[Audio] init: Context erstellt. state=', this.audioContext.state, 'rate=', this.audioContext.sampleRate); // Autoplay-Policy: Context sofort im User-Gesture fortsetzen if (this.audioContext.state === 'suspended') { @@ -496,9 +503,17 @@ export default { await this.audioContext.resume(); if (import.meta.env?.DEV) console.log('[Audio] init: state nach resume=', this.audioContext.state); } - const generator = new NoiseGenerator(); - this.motorSound = new MotorSound(this.audioContext, generator); - await this.motorSound.init(); + if (!this.motorSound) { + // Ggf. globalen Motor übernehmen + if (window.__TaxiMotorSound) { + this.motorSound = window.__TaxiMotorSound; + } else { + const generator = new NoiseGenerator(); + this.motorSound = new MotorSound(this.audioContext, generator); + await this.motorSound.init(); + window.__TaxiMotorSound = this.motorSound; + } + } if (import.meta.env?.DEV) console.log('[Audio] init: MotorSound initialisiert'); // Falls bereits Bewegung anliegt, Sound direkt starten const speedKmh = this.taxi.speed * 5; @@ -524,10 +539,25 @@ export default { const isMoving = speedKmh > 0; if (import.meta.env?.DEV) console.log('[Audio] update:', { speedKmh, isMoving, ctx: this.audioContext?.state, playing: this.motorSound.isPlaying }); - // Start NICHT hier (kein User-Gesture). Nur Stop, wenn still. - if (!isMoving && this.motorSound.isPlaying) { - if (import.meta.env?.DEV) console.log('[Audio] update: motorSound.stop()'); - this.motorSound.stop(); + // Start NICHT hier (kein User-Gesture). Stop mit 1s Verzögerung, wenn still + if (!isMoving) { + if (this.motorStopTimeout == null && this.motorSound.isPlaying) { + this.motorStopTimeout = setTimeout(() => { + // Nur stoppen, wenn weiterhin keine Bewegung + const still = (this.taxi.speed * 5) <= 0; + if (still && this.motorSound && this.motorSound.isPlaying) { + if (import.meta.env?.DEV) console.log('[Audio] update: delayed motorSound.stop()'); + this.motorSound.stop(); + } + this.motorStopTimeout = null; + }, 500); + } + } else { + // Bewegung: ggf. geplanten Stopp abbrechen + if (this.motorStopTimeout) { + clearTimeout(this.motorStopTimeout); + this.motorStopTimeout = null; + } } if (isMoving) { @@ -546,12 +576,12 @@ export default { if (this.gameLoop) { cancelAnimationFrame(this.gameLoop); } - if (this.motorSound) { - this.motorSound.stop(); - } - if (this.audioContext) { - this.audioContext.close(); + if (this.motorSound) { this.motorSound.stop(); } + if (this.motorStopTimeout) { + clearTimeout(this.motorStopTimeout); + this.motorStopTimeout = null; } + // AudioContext bleibt global erhalten, nicht schließen document.removeEventListener('keydown', this.handleKeyDown); document.removeEventListener('keyup', this.handleKeyUp); if (this.audioUnlockHandler) { @@ -1298,7 +1328,8 @@ export default { ensureAudioUnlockedInEvent() { // Muss synchron im Event-Handler laufen (ohne await), damit Policies greifen if (!this.audioContext) { - this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); + this.audioContext = window.__TaxiAudioContext || new (window.AudioContext || window.webkitAudioContext)(); + window.__TaxiAudioContext = this.audioContext; } try { if (this.audioContext.state === 'suspended') { @@ -1308,10 +1339,14 @@ export default { // ignore } if (!this.motorSound) { - const generator = new NoiseGenerator(); - this.motorSound = new MotorSound(this.audioContext, generator); - // nicht awaiten, bleibt im gleichen Event-Frame - this.motorSound.init(); + this.motorSound = window.__TaxiMotorSound; + if (!this.motorSound) { + const generator = new NoiseGenerator(); + this.motorSound = new MotorSound(this.audioContext, generator); + // nicht awaiten, bleibt im gleichen Event-Frame + this.motorSound.init(); + window.__TaxiMotorSound = this.motorSound; + } } },