diff --git a/frontend/src/views/minigames/TaxiGame.vue b/frontend/src/views/minigames/TaxiGame.vue index e876396..872dabb 100644 --- a/frontend/src/views/minigames/TaxiGame.vue +++ b/frontend/src/views/minigames/TaxiGame.vue @@ -287,22 +287,52 @@ export default { }, updateCurrentTile() { - // Berechne aktuelle Tile-Position basierend auf Taxi-Position - if (this.currentMap && this.currentMap.mapData) { - const mapData = this.currentMap.mapData; - const rows = mapData.length; - const cols = mapData[0] ? mapData[0].length : 0; - - // Da das Taxi nur in einem 400x400px Canvas ist, verwende das erste Tile der Map - // Das sollte das korrekte Tile sein, das in der Map definiert ist - this.currentTile.row = 0; - this.currentTile.col = 0; - - - // Stelle sicher, dass Taxi innerhalb des Canvas bleibt - this.taxi.x = Math.max(0, Math.min(this.canvas.width - this.taxi.width, this.taxi.x)); - this.taxi.y = Math.max(0, Math.min(this.canvas.height - this.taxi.height, this.taxi.y)); + // Wechsel auf benachbarte Tiles, sobald der Rand erreicht wird + if (!this.currentMap || !this.currentMap.mapData) return; + const mapData = this.currentMap.mapData; + const rows = mapData.length; + const cols = mapData[0] ? mapData[0].length : 0; + const tileSize = this.tiles.size; // 500px + + let newRow = this.currentTile.row; + let newCol = this.currentTile.col; + let moved = false; + + // Nach rechts: sobald rechte Kante den Rand erreicht (>=) + if (this.taxi.x + this.taxi.width >= tileSize && newCol < cols - 1) { + this.taxi.x = 0; // direkt an linken Rand des neuen Tiles + newCol += 1; + moved = true; } + // Nach links: sobald linke Kante den Rand erreicht (<= 0) + if (!moved && this.taxi.x <= 0 && newCol > 0) { + this.taxi.x = tileSize - this.taxi.width; // direkt an rechten Rand des neuen Tiles + newCol -= 1; + moved = true; + } + // Nach unten: sobald untere Kante den Rand erreicht (>=) + if (!moved && this.taxi.y + this.taxi.height >= tileSize && newRow < rows - 1) { + this.taxi.y = 0; // direkt an oberen Rand des neuen Tiles + newRow += 1; + moved = true; + } + // Nach oben: sobald obere Kante den Rand erreicht (<= 0) + if (!moved && this.taxi.y <= 0 && newRow > 0) { + this.taxi.y = tileSize - this.taxi.height; // direkt an unteren Rand des neuen Tiles + newRow -= 1; + moved = true; + } + + // Falls Wechsel möglich war, übernehme neue Tile-Position + if (moved) { + this.currentTile.row = newRow; + this.currentTile.col = newCol; + return; + } + + // An den äußeren Grenzen der Map: innerhalb des aktuellen Tiles halten + this.taxi.x = Math.max(0, Math.min(tileSize - this.taxi.width, this.taxi.x)); + this.taxi.y = Math.max(0, Math.min(tileSize - this.taxi.height, this.taxi.y)); }, setupEventListeners() { @@ -1007,10 +1037,10 @@ export default { async handleCanvasClick(event) { // AudioContext bei erster Benutzerinteraktion initialisieren if (import.meta.env?.DEV) console.log('[Audio] CanvasClick: start, hasCtx=', !!this.audioContext); - await this.initAudioOnUserInteraction(); + this.ensureAudioUnlockedInEvent(); if (this.audioContext && this.audioContext.state === 'suspended') { if (import.meta.env?.DEV) console.log('[Audio] CanvasClick: resume()'); - await this.audioContext.resume().catch(() => {}); + this.audioContext.resume().catch(() => {}); if (import.meta.env?.DEV) console.log('[Audio] CanvasClick: state=', this.audioContext.state); } // Motor ggf. direkt starten (Klick ist User-Geste) @@ -1025,10 +1055,10 @@ export default { // AudioContext bei erster Benutzerinteraktion initialisieren if (import.meta.env?.DEV) console.log('[Audio] KeyDown: key=', event.key, 'hasCtx=', !!this.audioContext); - await this.initAudioOnUserInteraction(); + this.ensureAudioUnlockedInEvent(); if (this.audioContext && this.audioContext.state === 'suspended') { if (import.meta.env?.DEV) console.log('[Audio] KeyDown: resume()'); - await this.audioContext.resume().catch(() => {}); + this.audioContext.resume().catch(() => {}); } // Bei Beschleunigungs-Key Motor starten (User-Geste garantiert) if ((event.key === 'ArrowUp' || event.key === 'w' || event.key === 'W') && this.motorSound && !this.motorSound.isPlaying) { @@ -1045,6 +1075,26 @@ export default { event.preventDefault(); }, + + ensureAudioUnlockedInEvent() { + // Muss synchron im Event-Handler laufen (ohne await), damit Policies greifen + if (!this.audioContext) { + this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); + } + try { + if (this.audioContext.state === 'suspended') { + this.audioContext.resume(); + } + } catch (e) { + // 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(); + } + }, handleKeyUp(event) { this.keys[event.key] = false;