diff --git a/frontend/src/dialogues/standard/MessageDialog.vue b/frontend/src/dialogues/standard/MessageDialog.vue index f78be92..5be37ad 100644 --- a/frontend/src/dialogues/standard/MessageDialog.vue +++ b/frontend/src/dialogues/standard/MessageDialog.vue @@ -67,14 +67,27 @@ export default { this.parameters = parameters; this.onClose = onClose; this.$refs.dialog.open(); + // Event Listener für Enter-Taste hinzufügen + this.$nextTick(() => { + document.addEventListener('keydown', this.handleKeyDown); + }); }, close() { this.$refs.dialog.close(); + // Event Listener entfernen + document.removeEventListener('keydown', this.handleKeyDown); // Rufe Callback auf, wenn vorhanden if (this.onClose && typeof this.onClose === 'function') { this.onClose(); } }, + handleKeyDown(event) { + // Schließe Dialog bei Enter-Taste + if (event.key === 'Enter' || event.keyCode === 13) { + event.preventDefault(); + this.close(); + } + }, interpolateParameters(text) { // Ersetze {key} Platzhalter mit den entsprechenden Werten let result = text; @@ -93,6 +106,10 @@ export default { console.log('Final result:', result); return result; } + }, + beforeDestroy() { + // Stelle sicher, dass Event Listener entfernt wird + document.removeEventListener('keydown', this.handleKeyDown); } }; diff --git a/frontend/src/views/minigames/TaxiGame.vue b/frontend/src/views/minigames/TaxiGame.vue index 8e3f2f3..13920dc 100644 --- a/frontend/src/views/minigames/TaxiGame.vue +++ b/frontend/src/views/minigames/TaxiGame.vue @@ -246,6 +246,8 @@ export default { bonusMultiplier: 15, // Bonus pro Tile timePerTile: 8, // Sekunden pro Tile fuel: 100, + isRefueling: false, + refuelTimer: null, currentLevel: 1, gameRunning: false, crashes: 0, @@ -1054,6 +1056,82 @@ export default { }); }, + // Prüft, ob das Taxi im Tank-Bereich ist und stillsteht + checkRefuelingConditions() { + const tileType = this.getCurrentTileType(); + + // Nur auf Fuel-Tiles prüfen + if (tileType !== 'fuelhorizontal' && tileType !== 'fuelvertical') { + return false; + } + + // Taxi muss stillstehen (Geschwindigkeit = 0) + if (this.taxi.speed !== 0) { + return false; + } + + // Prüfe Position im Tank-Bereich (absolute Koordinaten) + if (tileType === 'fuelhorizontal') { + // Y-Bereich zwischen 0.195 und 0.299 (relativ) = 97.5px und 149.5px (absolut) + const minY = 0.195 * 500; // 97.5px + const maxY = 0.299 * 500; // 149.5px + return this.taxi.y >= minY && this.taxi.y <= maxY; + } else if (tileType === 'fuelvertical') { + // X-Bereich zwischen 0.701 und 0.805 (relativ) = 350.5px und 402.5px (absolut) + const minX = 0.701 * 500; // 350.5px + const maxX = 0.805 * 500; // 402.5px + return this.taxi.x >= minX && this.taxi.x <= maxX; + } + + return false; + }, + + // Startet das Tanken + startRefueling() { + if (this.isRefueling || this.fuel >= 100) { + return; // Bereits am Tanken oder Tank voll + } + + this.isRefueling = true; + + // Tanken alle 0.1 Sekunden (100ms) + this.refuelTimer = setInterval(() => { + if (!this.checkRefuelingConditions()) { + this.stopRefueling(); + return; + } + + // Tanke 0.1% pro 0.1 Sekunden + this.fuel = Math.min(100, this.fuel + 0.1); + + // Stoppe wenn Tank voll + if (this.fuel >= 100) { + this.stopRefueling(); + } + }, 100); + }, + + // Stoppt das Tanken + stopRefueling() { + if (this.refuelTimer) { + clearInterval(this.refuelTimer); + this.refuelTimer = null; + } + this.isRefueling = false; + }, + + // Behandelt leeren Tank - Crash und Tank auffüllen + handleEmptyTank() { + // Stoppe das Tanken falls aktiv + this.stopRefueling(); + + // Crash durch leeren Tank + this.countCrash('emptytank'); + + // Zeige Crash-Dialog + this.showCrashDialog('Leerer Tank! Der Tank wurde automatisch aufgefüllt.'); + }, + removePassengerFromWaitingList() { if (this.waitingPassengersList.length > 0) { // Entferne den ersten Passagier aus der Liste @@ -1307,6 +1385,23 @@ export default { this.fuel = Math.max(0, this.fuel - 0.01); } + // Prüfe auf leeren Tank - Crash wenn Tank leer + if (this.fuel <= 0) { + this.handleEmptyTank(); + return; // Stoppe weitere Verarbeitung nach Crash + } + + // Prüfe Tanken-Bedingungen + if (this.checkRefuelingConditions()) { + if (!this.isRefueling) { + this.startRefueling(); + } + } else { + if (this.isRefueling) { + this.stopRefueling(); + } + } + // Motorgeräusch aktualisieren this.updateMotorSound(); }, @@ -1733,8 +1828,7 @@ export default { this.redLightSincePenalty = (this.redLightSincePenalty || 0) + 1; if (this.redLightSincePenalty >= 3) { this.redLightSincePenalty = 0; - this.crashes += 1; - this.decrementVehicle('redlight'); + this.countCrash('redlight'); const msg = 'Du hast wegen Rotlicht-Übertretungen ein Auto verloren.'; const title = 'Hinweis'; this.$root?.$refs?.messageDialog?.open?.(msg, title, {}, () => { @@ -1831,6 +1925,14 @@ export default { } }, + countCrash(reason = '') { + this.crashes++; + this.decrementVehicle(reason); + this.taxi.speed = 0; + this.isPaused = true; // Zuerst pausieren + this.fuel = 100; + }, + handleCrash() { // Verhindere mehrfache Crashes in kurzer Zeit if (this.isPaused) { @@ -1839,9 +1941,7 @@ export default { } console.log('🚨 CRASH ERKANNT!'); - this.crashes++; - this.taxi.speed = 0; - this.isPaused = true; // Zuerst pausieren + this.countCrash('wall crashed'); // Motorgeräusch sofort stoppen if (this.motorSound && this.motorSound.isPlaying) { @@ -1862,7 +1962,6 @@ export default { // Test: Direkter Aufruf nach 3 Sekunden (falls Dialog-Callback nicht funktioniert) this.crashDialogTimeout = setTimeout(() => { - console.log('Test: Automatischer Reset nach 3 Sekunden'); this.handleCrashDialogClose(); }, 3000); console.log('Crash-Dialog wird angezeigt:', { @@ -1999,36 +2098,10 @@ export default { })); // Verwende die robuste Kollisionserkennung für diese Region - const result = this.polylineIntersectsRotatedRect(regionPoints, rotatedRect, tileType === 'fuelhorizontal', tileType === 'fuelhorizontal'); - - // Debug-Ausgabe nur für horizontale Fuel-Tiles - if (tileType === 'fuelhorizontal') { - console.log('🔍 KOLLISIONS-DEBUG (Fuel Horizontal):'); - console.log('Taxi Rect (absolut):', taxiRect); - console.log('Region Polylinie (absolut):', regionPoints); - console.log('Rotated Rect:', rotatedRect); - console.log('Kollisionsergebnis:', result); - console.log('Region (relativ aus JSON):', region); - console.log('Taxi position:', this.taxi.x, this.taxi.y); - console.log('Current tile size:', currentTileSize); - console.log('Original tile size:', originalTileSize); - console.log('---'); - } + const result = this.polylineIntersectsRotatedRect(regionPoints, rotatedRect); // Einheitliche Logik für alle Tiles: Taxi darf KEINE der Hindernis-Polylinien schneiden if (result.hit) { - // Crash - zeige Debug-Informationen nur für Fuel Horizontal Tiles - if (tileType === 'fuelhorizontal') { - console.log('🚨 CRASH auf Fuel Horizontal Tile:'); - console.log('Taxi Rect (absolut):', taxiRect); - console.log('Crash Region Polylinie (absolut):', regionPoints); - console.log('Rotated Rect:', rotatedRect); - console.log('Crash Hits:', result.hits); - console.log('Region (relativ aus JSON):', region); - console.log('Taxi position:', this.taxi.x, this.taxi.y); - console.log('=== CRASH ENDE ==='); - } - return false; // Kollision mit Hindernis = Crash } } @@ -2082,24 +2155,11 @@ export default { }, // Testet, ob eine Polyline (Liste von Punkten) ein rotiertes Rechteck schneidet - polylineIntersectsRotatedRect(polyline, rect, debug = false, eps = 1e-9) { + polylineIntersectsRotatedRect(polyline, rect) { const { cx, cy, theta, hx, hy } = rect; - - // Debug-Ausgabe nur wenn explizit angefordert - if (debug) { - console.log('🔧 polylineIntersectsRotatedRect DEBUG (KORRIGIERT):'); - console.log('Polyline:', polyline); - console.log('Rect:', rect); - console.log('Rotation theta:', theta, 'rad =', (theta * 180 / Math.PI), 'deg'); - } - // KORREKTUR: Transformiere die Polyline in das lokale Koordinatensystem des Rechtecks + // Transformiere die Polyline in das lokale Koordinatensystem des Rechtecks const localPolyline = polyline.map(p => this.transformToLocal(p.x, p.y, cx, cy, theta)); - - if (debug) { - console.log('Transformierte Polyline (lokal):', localPolyline); - console.log('AABB bounds (lokal): x=[', -hx, ',', hx, '], y=[', -hy, ',', hy, ']'); - } // AABB-Grenzen im lokalen Koordinatensystem const AABB_minX = -hx; @@ -2112,13 +2172,7 @@ export default { const p = localPolyline[i]; const inX = p.x >= AABB_minX && p.x <= AABB_maxX; const inY = p.y >= AABB_minY && p.y <= AABB_maxY; - if (debug) { - console.log(` Punkt ${i}: (${p.x.toFixed(2)}, ${p.y.toFixed(2)}) - In AABB: ${inX && inY}`); - } if (inX && inY) { - if (debug) { - console.log(`✅ Kollision: Polyline-Punkt ${i} liegt im rotierten Rechteck`); - } return { hit: true, type: 'point_in_rect' }; } } @@ -2129,19 +2183,10 @@ export default { const B = localPolyline[i + 1]; if (this.lineSegmentIntersectsRect(A.x, A.y, B.x, B.y, AABB_minX, AABB_minY, AABB_maxX, AABB_maxY)) { - if (debug) { - console.log(`✅ Kollision: Polyline-Segment ${i} schneidet rotiertes Rechteck`); - } return { hit: true, type: 'segment_intersects_rect' }; } } - // 3. Prüfe ob das Rechteck vollständig innerhalb der Polyline liegt - // (Nur für geschlossene Polygone relevant - hier überspringen wir das) - - if (debug) { - console.log(`❌ Keine Kollision gefunden`); - } return { hit: false }; },