Änderung: Überarbeitung der TaxiGame.vue zur Verbesserung der Spielmechanik und Benutzeroberfläche

Änderungen:
- Entfernung der alten Pause-Anzeige und Integration eines neuen Tacho-Displays zur Geschwindigkeitsanzeige.
- Anpassung der Spielparameter, einschließlich der Taxi-Position und der Canvas-Größe auf 500x500px.
- Implementierung einer neuen Geschwindigkeitsregelung mit 5er-Schritten und Anpassung der Lenkgeschwindigkeit basierend auf der aktuellen Geschwindigkeit.
- Verbesserung der Benutzeroberfläche durch zentrierte Layouts und optimierte CSS-Klassen.

Diese Anpassungen verbessern die Benutzererfahrung und die Spielmechanik im Taxi-Minispiel erheblich.
This commit is contained in:
Torsten Schulz (local)
2025-09-15 23:29:31 +02:00
parent 3f33da06e5
commit 4a126c552d

View File

@@ -12,16 +12,6 @@
<div class="game-layout"> <div class="game-layout">
<!-- Spielbrett (links) --> <!-- Spielbrett (links) -->
<div class="game-board-section"> <div class="game-board-section">
<!-- Pause-Anzeige -->
<div v-if="showPauseOverlay" class="pause-overlay">
<div class="pause-message">
<h2>{{ $t('minigames.taxi.paused') }}</h2>
<button @click="togglePause" class="resume-button">
{{ $t('minigames.taxi.resume') }}
</button>
</div>
</div>
<!-- Spielbereich mit Canvas und Legende --> <!-- Spielbereich mit Canvas und Legende -->
<div class="game-area"> <div class="game-area">
<!-- Legende (links) --> <!-- Legende (links) -->
@@ -70,17 +60,39 @@
</div> </div>
</div> </div>
<!-- Spiel-Canvas --> <!-- Spiel-Canvas mit Tacho -->
<div class="game-canvas-container"> <div class="game-canvas-section">
<canvas <!-- Tacho-Display -->
ref="gameCanvas" <div class="tacho-display">
width="400" <div class="tacho-speed">
height="400" <span class="tacho-icon"></span>
class="game-canvas" <span class="speed-value">{{ taxi.speed * 5 }}</span>
@click="handleCanvasClick" <span class="speed-unit">km/h</span>
@keydown="handleKeyDown" </div>
tabindex="0" </div>
></canvas>
<!-- Pause-Anzeige -->
<div v-if="showPauseOverlay" class="pause-overlay">
<div class="pause-message">
<h2>{{ $t('minigames.taxi.paused') }}</h2>
<button @click="togglePause" class="resume-button">
{{ $t('minigames.taxi.resume') }}
</button>
</div>
</div>
<!-- Canvas -->
<div class="game-canvas-container">
<canvas
ref="gameCanvas"
width="500"
height="500"
class="game-canvas"
@click="handleCanvasClick"
@keydown="handleKeyDown"
tabindex="0"
></canvas>
</div>
</div> </div>
</div> </div>
@@ -193,20 +205,22 @@ export default {
gameRunning: false, gameRunning: false,
crashes: 0, crashes: 0,
gameLoop: null, gameLoop: null,
lastSpeedChange: 0,
speedChangeInterval: 100, // 200ms = 0.2 Sekunden
canvas: null, canvas: null,
ctx: null, ctx: null,
minimapCanvas: null, minimapCanvas: null,
minimapCtx: null, minimapCtx: null,
isStatsExpanded: true, isStatsExpanded: true,
taxi: { taxi: {
x: 200, // Mitte des 400x400px Tiles x: 250, // Mitte des 400x400px Tiles
y: 200, // Mitte des 400x400px Tiles y: 250, // Mitte des 400x400px Tiles
width: 30, // Skalierte Breite (50px Höhe * 297/506) width: 30, // Skalierte Breite (50px Höhe * 297/506)
height: 50, // 50px Höhe height: 50, // 50px Höhe
angle: 0, // Fahrtrichtung angle: 0, // Fahrtrichtung
imageAngle: Math.PI / 2, // Bildrotation (90° nach rechts) imageAngle: Math.PI / 2, // Bildrotation (90° nach rechts)
speed: 0, speed: 0,
maxSpeed: 3, maxSpeed: 24, // 24 = 120 km/h (5er-Schritte: 0, 5, 10, ..., 120)
image: null // Taxi-Bild image: null // Taxi-Bild
}, },
currentTile: { currentTile: {
@@ -214,7 +228,7 @@ export default {
col: 0 col: 0
}, },
tiles: { tiles: {
size: 400, // 400x400px pro Tile size: 500, // 400x400px pro Tile
images: {} images: {}
}, },
maps: [], // Geladene Maps aus der Datenbank maps: [], // Geladene Maps aus der Datenbank
@@ -260,8 +274,8 @@ export default {
this.canvas.focus(); this.canvas.focus();
// Taxi in die Mitte des 400x400px Tiles positionieren // Taxi in die Mitte des 400x400px Tiles positionieren
this.taxi.x = 200 - this.taxi.width/2; // Zentriert in der Mitte this.taxi.x = 250 - this.taxi.width/2; // Zentriert in der Mitte
this.taxi.y = 200 - this.taxi.height/2; // Zentriert in der Mitte this.taxi.y = 250 - this.taxi.height/2; // Zentriert in der Mitte
this.taxi.angle = 0; // Fahrtrichtung nach oben this.taxi.angle = 0; // Fahrtrichtung nach oben
this.taxi.speed = 0; // Geschwindigkeit zurücksetzen this.taxi.speed = 0; // Geschwindigkeit zurücksetzen
@@ -275,8 +289,8 @@ export default {
updateCanvasSize() { updateCanvasSize() {
// Canvas ist immer 400x400px für ein einzelnes Tile // Canvas ist immer 400x400px für ein einzelnes Tile
this.canvas.width = 400; this.canvas.width = 500;
this.canvas.height = 400; this.canvas.height = 500;
}, },
updateCurrentTile() { updateCurrentTile() {
@@ -379,7 +393,7 @@ export default {
} }
// Fallback: Mitte des Spielfelds // Fallback: Mitte des Spielfelds
return { x: 200, y: 200 }; return { x: 250, y: 250 };
}, },
getRandomOffRoadPosition() { getRandomOffRoadPosition() {
@@ -434,34 +448,50 @@ export default {
}, },
updateTaxi() { updateTaxi() {
// Beschleunigung bei gedrücktem Pfeil nach oben // Prüfe ob das Spiel pausiert ist
if (this.keys['ArrowUp'] || this.keys['w'] || this.keys['W']) { if (this.isPaused) {
this.taxi.speed = Math.min(this.taxi.speed + 0.015625, this.taxi.maxSpeed); return;
} }
// Abbremsen bei gedrücktem Pfeil nach unten const currentTime = Date.now();
if (this.keys['ArrowDown'] || this.keys['x'] || this.keys['X']) {
this.taxi.speed = Math.max(this.taxi.speed - 0.0625, 0); // Bremsen bis 0, nicht rückwärts // Prüfe ob genug Zeit vergangen ist für Geschwindigkeitsänderung
if (currentTime - this.lastSpeedChange >= this.speedChangeInterval) {
// Beschleunigung bei gedrücktem Pfeil nach oben (5er-Schritte)
if (this.keys['ArrowUp'] || this.keys['w'] || this.keys['W']) {
this.taxi.speed = Math.min(this.taxi.speed + 1, this.taxi.maxSpeed);
this.lastSpeedChange = currentTime;
}
// Abbremsen bei gedrücktem Pfeil nach unten (5er-Schritte)
if (this.keys['ArrowDown'] || this.keys['x'] || this.keys['X']) {
this.taxi.speed = Math.max(this.taxi.speed - 1, 0); // Bremsen bis 0, nicht rückwärts
this.lastSpeedChange = currentTime;
}
} }
// Lenkung // Lenkung - abhängig von der Geschwindigkeit
const baseSteeringSpeed = 0.07; // Basis-Lenkgeschwindigkeit für 20 km/h (Stufe 4)
const currentSpeedLevel = this.taxi.speed; // 0-24 (entspricht 0-120 km/h)
const steeringSpeed = baseSteeringSpeed * (currentSpeedLevel / 4); // Skaliert auf Stufe 4
if (this.keys['ArrowLeft'] || this.keys['a'] || this.keys['A']) { if (this.keys['ArrowLeft'] || this.keys['a'] || this.keys['A']) {
this.taxi.angle -= 0.025; this.taxi.angle -= steeringSpeed;
} }
if (this.keys['ArrowRight'] || this.keys['d'] || this.keys['D']) { if (this.keys['ArrowRight'] || this.keys['d'] || this.keys['D']) {
this.taxi.angle += 0.025; this.taxi.angle += steeringSpeed;
} }
// Aktualisiere Position // Aktualisiere Position (1/4 der ursprünglichen Bewegung)
this.taxi.x += Math.cos(this.taxi.angle) * this.taxi.speed; this.taxi.x += Math.cos(this.taxi.angle) * this.taxi.speed * 0.25;
this.taxi.y += Math.sin(this.taxi.angle) * this.taxi.speed; this.taxi.y += Math.sin(this.taxi.angle) * this.taxi.speed * 0.25;
// Aktualisiere aktuelle Tile-Position // Aktualisiere aktuelle Tile-Position
this.updateCurrentTile(); this.updateCurrentTile();
// Verbrauche Treibstoff // Verbrauche Treibstoff
if (Math.abs(this.taxi.speed) > 0.1) { if (Math.abs(this.taxi.speed) > 0.1) {
this.fuel = Math.max(0, this.fuel - 0.1); this.fuel = Math.max(0, this.fuel - 0.01);
} }
}, },
@@ -557,6 +587,12 @@ export default {
const crashMessage = `Du hattest einen Unfall! Crashes: ${this.crashes}`; const crashMessage = `Du hattest einen Unfall! Crashes: ${this.crashes}`;
const crashTitle = 'Unfall!'; const crashTitle = 'Unfall!';
this.$root?.$refs?.messageDialog?.open?.(crashMessage, crashTitle, {}, this.handleCrashDialogClose); this.$root?.$refs?.messageDialog?.open?.(crashMessage, crashTitle, {}, this.handleCrashDialogClose);
// Test: Direkter Aufruf nach 3 Sekunden (falls Dialog-Callback nicht funktioniert)
setTimeout(() => {
console.log('Test: Automatischer Reset nach 3 Sekunden');
this.handleCrashDialogClose();
}, 3000);
console.log('Crash-Dialog wird angezeigt:', { console.log('Crash-Dialog wird angezeigt:', {
crashes: this.crashes, crashes: this.crashes,
isPaused: this.isPaused, isPaused: this.isPaused,
@@ -577,18 +613,24 @@ export default {
this.isPaused = false; this.isPaused = false;
this.showPauseOverlay = false; this.showPauseOverlay = false;
console.log('Nach Dialog-Close - isPaused:', this.isPaused, 'showPauseOverlay:', this.showPauseOverlay);
// Taxi-Position zurücksetzen
this.resetTaxiPosition();
// Fokus zurück auf Canvas setzen // Fokus zurück auf Canvas setzen
this.$nextTick(() => { this.$nextTick(() => {
if (this.canvas) { if (this.canvas) {
this.canvas.focus(); this.canvas.focus();
} }
console.log('Nach nextTick - isPaused:', this.isPaused);
}); });
}, },
resetTaxiPosition() { resetTaxiPosition() {
// Taxi in der Mitte des Screens platzieren // Taxi in der Mitte des Screens platzieren
this.taxi.x = 200 - this.taxi.width/2; this.taxi.x = 250 - this.taxi.width/2;
this.taxi.y = 200 - this.taxi.height/2; this.taxi.y = 250 - this.taxi.height/2;
this.taxi.speed = 0; this.taxi.speed = 0;
this.taxi.angle = 0; this.taxi.angle = 0;
@@ -612,7 +654,7 @@ export default {
const tileType = this.getCurrentTileType(); const tileType = this.getCurrentTileType();
const streetTileType = this.mapTileTypeToStreetCoordinates(tileType); const streetTileType = this.mapTileTypeToStreetCoordinates(tileType);
const originalTileSize = streetCoordinates.getOriginalTileSize(); // 640px const originalTileSize = streetCoordinates.getOriginalTileSize(); // 640px
const currentTileSize = 400; // Aktuelle Render-Größe const currentTileSize = 500; // Aktuelle Render-Größe
// Hole die Polygon-Koordinaten für dieses Tile // Hole die Polygon-Koordinaten für dieses Tile
const regions = streetCoordinates.getDriveableRegions(streetTileType, originalTileSize); const regions = streetCoordinates.getDriveableRegions(streetTileType, originalTileSize);
@@ -915,8 +957,8 @@ export default {
this.money = 0; this.money = 0;
this.passengersDelivered = 0; this.passengersDelivered = 0;
this.fuel = 100; this.fuel = 100;
this.taxi.x = 400; this.taxi.x = 250;
this.taxi.y = 300; this.taxi.y = 250;
this.taxi.angle = 0; this.taxi.angle = 0;
this.taxi.speed = 0; this.taxi.speed = 0;
this.generateLevel(); this.generateLevel();
@@ -1010,8 +1052,8 @@ export default {
this.updateCanvasSize(); this.updateCanvasSize();
// Taxi in die Mitte des 400x400px Tiles positionieren // Taxi in die Mitte des 400x400px Tiles positionieren
this.taxi.x = 200 - this.taxi.width/2; // Zentriert in der Mitte this.taxi.x = 250 - this.taxi.width/2; // Zentriert in der Mitte
this.taxi.y = 200 - this.taxi.height/2; // Zentriert in der Mitte this.taxi.y = 250 - this.taxi.height/2; // Zentriert in der Mitte
this.taxi.angle = 0; // Fahrtrichtung nach oben this.taxi.angle = 0; // Fahrtrichtung nach oben
this.taxi.speed = 0; // Geschwindigkeit zurücksetzen this.taxi.speed = 0; // Geschwindigkeit zurücksetzen
@@ -1106,16 +1148,16 @@ export default {
const cols = mapData[0] ? mapData[0].length : 0; const cols = mapData[0] ? mapData[0].length : 0;
const maxTiles = Math.max(rows, cols); const maxTiles = Math.max(rows, cols);
const tileSize = Math.min(canvas.width / maxTiles, canvas.height / maxTiles); const tileSize = Math.min(canvas.width / maxTiles, canvas.height / maxTiles);
scaleX = tileSize / 400; // 400 ist die neue Tile-Größe scaleX = tileSize / 500; // 400 ist die neue Tile-Größe
scaleY = tileSize / 400; scaleY = tileSize / 500;
offsetX = (canvas.width - cols * tileSize) / 2; offsetX = (canvas.width - cols * tileSize) / 2;
offsetY = (canvas.height - rows * tileSize) / 2; offsetY = (canvas.height - rows * tileSize) / 2;
} else { } else {
// Fallback für statische Map // Fallback für statische Map
const maxTiles = 8; const maxTiles = 8;
const tileSize = Math.min(canvas.width / maxTiles, canvas.height / maxTiles); const tileSize = Math.min(canvas.width / maxTiles, canvas.height / maxTiles);
scaleX = tileSize / 400; scaleX = tileSize / 500;
scaleY = tileSize / 400; scaleY = tileSize / 500;
offsetX = (canvas.width - 8 * tileSize) / 2; offsetX = (canvas.width - 8 * tileSize) / 2;
offsetY = (canvas.height - 8 * tileSize) / 2; offsetY = (canvas.height - 8 * tileSize) / 2;
} }
@@ -1144,8 +1186,8 @@ export default {
// Taxi (blau) - Position basierend auf aktueller Tile-Position // Taxi (blau) - Position basierend auf aktueller Tile-Position
ctx.fillStyle = '#2196F3'; ctx.fillStyle = '#2196F3';
ctx.beginPath(); ctx.beginPath();
const taxiGlobalX = this.currentTile.col * 400 + this.taxi.x; const taxiGlobalX = this.currentTile.col * 500 + this.taxi.x;
const taxiGlobalY = this.currentTile.row * 400 + this.taxi.y; const taxiGlobalY = this.currentTile.row * 500 + this.taxi.y;
ctx.arc(offsetX + taxiGlobalX * scaleX, offsetY + taxiGlobalY * scaleY, 3, 0, 2 * Math.PI); ctx.arc(offsetX + taxiGlobalX * scaleX, offsetY + taxiGlobalY * scaleY, 3, 0, 2 * Math.PI);
ctx.fill(); ctx.fill();
@@ -1205,6 +1247,51 @@ export default {
align-items: flex-start; align-items: flex-start;
} }
/* Game Canvas Section */
.game-canvas-section {
display: flex;
flex-direction: column;
align-items: center;
width: 500px;
margin: 0 auto; /* Zentriert den gesamten Container */
}
/* Tacho-Display */
.tacho-display {
width: 500px; /* Gleiche Breite wie das zentrale Tile */
background: #f8f9fa;
border: 1px solid #ddd;
border-radius: 4px;
padding: 8px 12px;
margin: 0; /* Kein Margin */
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
box-sizing: border-box; /* Padding wird in die Breite eingerechnet */
}
.tacho-speed {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 6px;
font-size: 10pt;
color: #333;
font-weight: 500;
}
.tacho-icon {
font-size: 10pt;
}
.speed-value {
font-weight: bold;
color: #2196F3;
}
.speed-unit {
color: #666;
font-size: 9pt;
}
.game-board-section { .game-board-section {
flex: 1; flex: 1;
display: flex; display: flex;
@@ -1220,6 +1307,7 @@ export default {
align-items: flex-start; align-items: flex-start;
width: 100%; width: 100%;
max-width: 1200px; max-width: 1200px;
justify-content: center; /* Zentriert den Inhalt */
} }
.sidebar-section { .sidebar-section {
@@ -1435,9 +1523,10 @@ export default {
/* Game Canvas */ /* Game Canvas */
.game-canvas-container { .game-canvas-container {
margin: 20px 0; margin: 0; /* Kein Margin */
text-align: center; text-align: center;
flex: 1; width: 500px; /* Feste Breite wie das Tacho-Display */
box-sizing: border-box; /* Border wird in die Breite eingerechnet */
} }
.game-canvas { .game-canvas {