Änderung: Verbesserung der MessageDialog-Komponente und Integration von Übersetzungen
Änderungen: - Anpassung des MessageDialog zur Unterstützung von dynamischen Titeln und Schaltflächen mit Übersetzungen. - Implementierung einer Methode zur Interpolation von Platzhaltern in Nachrichten. - Erweiterung der i18n-Übersetzungen für Crash-Nachrichten im Minispiel. - Aktualisierung der TaxiGame.vue zur Anzeige von Unfallmeldungen über den MessageDialog. Diese Anpassungen verbessern die Benutzererfahrung durch mehrsprachige Unterstützung und dynamische Nachrichten im Taxi-Minispiel.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<DialogWidget ref="dialog" title="message.title" :show-close="true" :buttons="buttons" :modal="true" width="25em"
|
<DialogWidget ref="dialog" :title="translatedTitle" :show-close="true" :buttons="translatedButtons" :modal="true" width="25em"
|
||||||
height="15em" name="MessageDialog" :isTitleTranslated=true>
|
height="15em" name="MessageDialog" :isTitleTranslated=false>
|
||||||
<div class="message-content">
|
<div class="message-content">
|
||||||
<p>{{ translatedMessage }}</p>
|
<p>{{ translatedMessage }}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -18,26 +18,80 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
message: '',
|
message: '',
|
||||||
|
title: '',
|
||||||
|
parameters: {},
|
||||||
|
onClose: null,
|
||||||
buttons: [
|
buttons: [
|
||||||
{ text: 'message.close', action: 'close' }
|
{ text: 'tr:message.close', action: 'close' }
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
translatedTitle() {
|
||||||
|
if (this.title.startsWith('tr:')) {
|
||||||
|
return this.$t(this.title.substring(3));
|
||||||
|
}
|
||||||
|
if (this.title) {
|
||||||
|
return this.title;
|
||||||
|
}
|
||||||
|
// Standard-Titel je nach Sprache
|
||||||
|
return this.$t('message.title');
|
||||||
|
},
|
||||||
translatedMessage() {
|
translatedMessage() {
|
||||||
if (this.message.startsWith('tr:')) {
|
if (this.message.startsWith('tr:')) {
|
||||||
return this.$t(this.message.substring(3));
|
const i18nKey = this.message.substring(3);
|
||||||
|
const translation = this.$t(i18nKey);
|
||||||
|
console.log('translatedMessage:', {
|
||||||
|
i18nKey: i18nKey,
|
||||||
|
translation: translation,
|
||||||
|
parameters: this.parameters,
|
||||||
|
allMinigames: this.$t('minigames'),
|
||||||
|
crashSection: this.$t('minigames.taxi.crash')
|
||||||
|
});
|
||||||
|
// Ersetze Parameter in der Übersetzung
|
||||||
|
return this.interpolateParameters(translation);
|
||||||
}
|
}
|
||||||
return this.message;
|
return this.message;
|
||||||
|
},
|
||||||
|
translatedButtons() {
|
||||||
|
return this.buttons.map(button => ({
|
||||||
|
...button,
|
||||||
|
text: button.text.startsWith('tr:') ? this.$t(button.text.substring(3)) : button.text
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
open(message) {
|
open(message, title = '', parameters = {}, onClose = null) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
|
this.title = title;
|
||||||
|
this.parameters = parameters;
|
||||||
|
this.onClose = onClose;
|
||||||
this.$refs.dialog.open();
|
this.$refs.dialog.open();
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
this.$refs.dialog.close();
|
this.$refs.dialog.close();
|
||||||
|
// Rufe Callback auf, wenn vorhanden
|
||||||
|
if (this.onClose && typeof this.onClose === 'function') {
|
||||||
|
this.onClose();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
interpolateParameters(text) {
|
||||||
|
// Ersetze {key} Platzhalter mit den entsprechenden Werten
|
||||||
|
let result = text;
|
||||||
|
console.log('interpolateParameters:', {
|
||||||
|
originalText: text,
|
||||||
|
parameters: this.parameters
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(this.parameters)) {
|
||||||
|
const placeholder = `{${key}}`;
|
||||||
|
const regex = new RegExp(placeholder.replace(/[{}]/g, '\\$&'), 'g');
|
||||||
|
result = result.replace(regex, value);
|
||||||
|
console.log(`Replaced ${placeholder} with ${value}:`, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Final result:', result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import enFalukant from './locales/en/falukant.json';
|
|||||||
import enPasswordReset from './locales/en/passwordReset.json';
|
import enPasswordReset from './locales/en/passwordReset.json';
|
||||||
import enBlog from './locales/en/blog.json';
|
import enBlog from './locales/en/blog.json';
|
||||||
import enMinigames from './locales/en/minigames.json';
|
import enMinigames from './locales/en/minigames.json';
|
||||||
|
import enMessage from './locales/en/message.json';
|
||||||
|
|
||||||
import deGeneral from './locales/de/general.json';
|
import deGeneral from './locales/de/general.json';
|
||||||
import deHeader from './locales/de/header.json';
|
import deHeader from './locales/de/header.json';
|
||||||
@@ -34,6 +35,7 @@ import deFalukant from './locales/de/falukant.json';
|
|||||||
import dePasswordReset from './locales/de/passwordReset.json';
|
import dePasswordReset from './locales/de/passwordReset.json';
|
||||||
import deBlog from './locales/de/blog.json';
|
import deBlog from './locales/de/blog.json';
|
||||||
import deMinigames from './locales/de/minigames.json';
|
import deMinigames from './locales/de/minigames.json';
|
||||||
|
import deMessage from './locales/de/message.json';
|
||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
en: {
|
en: {
|
||||||
@@ -53,6 +55,7 @@ const messages = {
|
|||||||
...enFalukant,
|
...enFalukant,
|
||||||
...enBlog,
|
...enBlog,
|
||||||
...enMinigames,
|
...enMinigames,
|
||||||
|
...enMessage,
|
||||||
},
|
},
|
||||||
de: {
|
de: {
|
||||||
'Ok': 'Ok',
|
'Ok': 'Ok',
|
||||||
@@ -72,6 +75,7 @@ const messages = {
|
|||||||
...deFalukant,
|
...deFalukant,
|
||||||
...deBlog,
|
...deBlog,
|
||||||
...deMinigames,
|
...deMinigames,
|
||||||
|
...deMessage,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
7
frontend/src/i18n/locales/de/message.json
Normal file
7
frontend/src/i18n/locales/de/message.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"message": {
|
||||||
|
"title": "Mitteilung",
|
||||||
|
"close": "Schließen",
|
||||||
|
"test": "Test funktioniert"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,7 +63,11 @@
|
|||||||
"deliverPassenger": "Passagier abliefern",
|
"deliverPassenger": "Passagier abliefern",
|
||||||
"refuel": "Tanken",
|
"refuel": "Tanken",
|
||||||
"startEngine": "Motor starten",
|
"startEngine": "Motor starten",
|
||||||
"stopEngine": "Motor stoppen"
|
"stopEngine": "Motor stoppen",
|
||||||
|
"crash": {
|
||||||
|
"title": "Unfall!",
|
||||||
|
"message": "Du hattest einen Unfall! Crashes: {crashes}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
frontend/src/i18n/locales/en/message.json
Normal file
6
frontend/src/i18n/locales/en/message.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"message": {
|
||||||
|
"title": "Notice",
|
||||||
|
"close": "Close"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,7 +63,11 @@
|
|||||||
"deliverPassenger": "Deliver Passenger",
|
"deliverPassenger": "Deliver Passenger",
|
||||||
"refuel": "Refuel",
|
"refuel": "Refuel",
|
||||||
"startEngine": "Start Engine",
|
"startEngine": "Start Engine",
|
||||||
"stopEngine": "Stop Engine"
|
"stopEngine": "Stop Engine",
|
||||||
|
"crash": {
|
||||||
|
"title": "Crash!",
|
||||||
|
"message": "You had an accident! Crashes: {crashes}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<!-- Spielbrett (links) -->
|
<!-- Spielbrett (links) -->
|
||||||
<div class="game-board-section">
|
<div class="game-board-section">
|
||||||
<!-- Pause-Anzeige -->
|
<!-- Pause-Anzeige -->
|
||||||
<div v-if="isPaused" class="pause-overlay">
|
<div v-if="showPauseOverlay" class="pause-overlay">
|
||||||
<div class="pause-message">
|
<div class="pause-message">
|
||||||
<h2>{{ $t('minigames.taxi.paused') }}</h2>
|
<h2>{{ $t('minigames.taxi.paused') }}</h2>
|
||||||
<button @click="togglePause" class="resume-button">
|
<button @click="togglePause" class="resume-button">
|
||||||
@@ -126,6 +126,11 @@
|
|||||||
<span class="stat-label">{{ $t('minigames.taxi.passengers') }}</span>
|
<span class="stat-label">{{ $t('minigames.taxi.passengers') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-row">
|
||||||
|
<span class="stat-value crash-value">{{ crashes }}</span>
|
||||||
|
<span class="stat-label">Unfälle</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="stat-row">
|
<div class="stat-row">
|
||||||
<span class="stat-value fuel-value">{{ fuel }}%</span>
|
<span class="stat-value fuel-value">{{ fuel }}%</span>
|
||||||
<span class="stat-label">{{ $t('minigames.taxi.fuel') }}</span>
|
<span class="stat-label">{{ $t('minigames.taxi.fuel') }}</span>
|
||||||
@@ -162,24 +167,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import streetCoordinates from '../../utils/streetCoordinates.js';
|
import streetCoordinates from '../../utils/streetCoordinates.js';
|
||||||
import apiClient from '../../utils/axios.js';
|
import apiClient from '../../utils/axios.js';
|
||||||
|
import StatusBar from '../../components/falukant/StatusBar.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TaxiGame',
|
name: 'TaxiGame',
|
||||||
|
components: {
|
||||||
|
StatusBar
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isPaused: false,
|
isPaused: false,
|
||||||
|
showPauseOverlay: false,
|
||||||
score: 0,
|
score: 0,
|
||||||
money: 0,
|
money: 0,
|
||||||
passengersDelivered: 0,
|
passengersDelivered: 0,
|
||||||
fuel: 100,
|
fuel: 100,
|
||||||
currentLevel: 1,
|
currentLevel: 1,
|
||||||
gameRunning: false,
|
gameRunning: false,
|
||||||
|
crashes: 0,
|
||||||
gameLoop: null,
|
gameLoop: null,
|
||||||
canvas: null,
|
canvas: null,
|
||||||
ctx: null,
|
ctx: null,
|
||||||
@@ -226,6 +238,22 @@ export default {
|
|||||||
this.cleanup();
|
this.cleanup();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// Mapping zwischen Spiel-Tile-Namen (lowercase) und streetCoordinates.json (camelCase)
|
||||||
|
mapTileTypeToStreetCoordinates(tileType) {
|
||||||
|
const mapping = {
|
||||||
|
'cornertopleft': 'cornerTopLeft',
|
||||||
|
'cornertopright': 'cornerTopRight',
|
||||||
|
'cornerbottomleft': 'cornerBottomLeft',
|
||||||
|
'cornerbottomright': 'cornerBottomRight',
|
||||||
|
'horizontal': 'horizontal',
|
||||||
|
'vertical': 'vertical',
|
||||||
|
'cross': 'cross',
|
||||||
|
'fuelhorizontal': 'fuelHorizontal',
|
||||||
|
'fuelvertical': 'fuelVertical'
|
||||||
|
};
|
||||||
|
return mapping[tileType] || tileType;
|
||||||
|
},
|
||||||
|
|
||||||
initializeGame() {
|
initializeGame() {
|
||||||
this.canvas = this.$refs.gameCanvas;
|
this.canvas = this.$refs.gameCanvas;
|
||||||
this.ctx = this.canvas.getContext('2d');
|
this.ctx = this.canvas.getContext('2d');
|
||||||
@@ -258,13 +286,11 @@ export default {
|
|||||||
const rows = mapData.length;
|
const rows = mapData.length;
|
||||||
const cols = mapData[0] ? mapData[0].length : 0;
|
const cols = mapData[0] ? mapData[0].length : 0;
|
||||||
|
|
||||||
// Berechne Tile-Koordinaten basierend auf Taxi-Position
|
// Da das Taxi nur in einem 400x400px Canvas ist, verwende das erste Tile der Map
|
||||||
const tileRow = Math.floor(this.taxi.y / this.tiles.size);
|
// Das sollte das korrekte Tile sein, das in der Map definiert ist
|
||||||
const tileCol = Math.floor(this.taxi.x / this.tiles.size);
|
this.currentTile.row = 0;
|
||||||
|
this.currentTile.col = 0;
|
||||||
|
|
||||||
// Begrenze auf Map-Grenzen
|
|
||||||
this.currentTile.row = Math.max(0, Math.min(rows - 1, tileRow));
|
|
||||||
this.currentTile.col = Math.max(0, Math.min(cols - 1, tileCol));
|
|
||||||
|
|
||||||
// Stelle sicher, dass Taxi innerhalb des Canvas bleibt
|
// 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.x = Math.max(0, Math.min(this.canvas.width - this.taxi.width, this.taxi.x));
|
||||||
@@ -342,7 +368,8 @@ export default {
|
|||||||
const relativeX = Math.random();
|
const relativeX = Math.random();
|
||||||
const relativeY = Math.random();
|
const relativeY = Math.random();
|
||||||
|
|
||||||
if (streetCoordinates.isPointDriveable(relativeX, relativeY, tileType, 1)) {
|
const streetTileType = this.mapTileTypeToStreetCoordinates(tileType);
|
||||||
|
if (streetCoordinates.isPointDriveable(relativeX, relativeY, streetTileType, 1)) {
|
||||||
return {
|
return {
|
||||||
x: tileCol * tileSize + relativeX * tileSize,
|
x: tileCol * tileSize + relativeX * tileSize,
|
||||||
y: tileRow * tileSize + relativeY * tileSize
|
y: tileRow * tileSize + relativeY * tileSize
|
||||||
@@ -370,7 +397,8 @@ export default {
|
|||||||
const relativeX = Math.random();
|
const relativeX = Math.random();
|
||||||
const relativeY = Math.random();
|
const relativeY = Math.random();
|
||||||
|
|
||||||
if (!streetCoordinates.isPointDriveable(relativeX, relativeY, tileType, 1)) {
|
const streetTileType = this.mapTileTypeToStreetCoordinates(tileType);
|
||||||
|
if (!streetCoordinates.isPointDriveable(relativeX, relativeY, streetTileType, 1)) {
|
||||||
return {
|
return {
|
||||||
x: tileCol * tileSize + relativeX * tileSize,
|
x: tileCol * tileSize + relativeX * tileSize,
|
||||||
y: tileRow * tileSize + relativeY * tileSize
|
y: tileRow * tileSize + relativeY * tileSize
|
||||||
@@ -396,7 +424,7 @@ export default {
|
|||||||
|
|
||||||
this.updateTaxi();
|
this.updateTaxi();
|
||||||
this.handlePassengerActions();
|
this.handlePassengerActions();
|
||||||
// this.checkCollisions(); // Temporär deaktiviert für freie Fahrt
|
this.checkCollisions();
|
||||||
this.render();
|
this.render();
|
||||||
|
|
||||||
// Minimap zeichnen
|
// Minimap zeichnen
|
||||||
@@ -493,44 +521,249 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
checkCollisions() {
|
checkCollisions() {
|
||||||
// Prüfe Straßenkollisionen
|
// Prüfe Straßenkollisionen nur wenn das Spiel nicht pausiert ist
|
||||||
if (!this.isTaxiOnRoad()) {
|
if (!this.isPaused && !this.isTaxiOnRoad()) {
|
||||||
this.taxi.speed = 0;
|
this.handleCrash();
|
||||||
this.score = Math.max(0, this.score - 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfe Hindernisse
|
// Prüfe Hindernisse nur wenn das Spiel nicht pausiert ist
|
||||||
|
if (!this.isPaused) {
|
||||||
this.obstacles.forEach(obstacle => {
|
this.obstacles.forEach(obstacle => {
|
||||||
if (this.checkCollision(this.taxi, obstacle)) {
|
if (this.checkCollision(this.taxi, obstacle)) {
|
||||||
|
this.handleCrash();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleCrash() {
|
||||||
|
// Verhindere mehrfache Crashes in kurzer Zeit
|
||||||
|
if (this.isPaused) {
|
||||||
|
console.log('Crash bereits erkannt, ignoriere weitere');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🚨 CRASH ERKANNT!');
|
||||||
|
this.crashes++;
|
||||||
this.taxi.speed = 0;
|
this.taxi.speed = 0;
|
||||||
this.score = Math.max(0, this.score - 5);
|
this.isPaused = true; // Zuerst pausieren
|
||||||
|
|
||||||
|
// Taxi sofort zurücksetzen
|
||||||
|
this.resetTaxiPosition();
|
||||||
|
|
||||||
|
// Dialog über globale MessageDialog öffnen
|
||||||
|
this.$nextTick(() => {
|
||||||
|
// Temporär direkte Übersetzung verwenden, bis i18n-Problem gelöst ist
|
||||||
|
const crashMessage = `Du hattest einen Unfall! Crashes: ${this.crashes}`;
|
||||||
|
const crashTitle = 'Unfall!';
|
||||||
|
this.$root?.$refs?.messageDialog?.open?.(crashMessage, crashTitle, {}, this.handleCrashDialogClose);
|
||||||
|
console.log('Crash-Dialog wird angezeigt:', {
|
||||||
|
crashes: this.crashes,
|
||||||
|
isPaused: this.isPaused,
|
||||||
|
taxiSpeed: this.taxi.speed,
|
||||||
|
messageTest: this.$t('message.test'),
|
||||||
|
crashMessage: this.$t('minigames.taxi.crash.message'),
|
||||||
|
allKeys: Object.keys(this.$t('minigames')),
|
||||||
|
taxiKeys: Object.keys(this.$t('minigames.taxi')),
|
||||||
|
crashKeys: Object.keys(this.$t('minigames.taxi.crash'))
|
||||||
|
});
|
||||||
|
|
||||||
|
// Spiel bleibt pausiert bis Dialog geschlossen wird
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
handleCrashDialogClose() {
|
||||||
|
console.log('Crash-Dialog geschlossen, Spiel wird fortgesetzt');
|
||||||
|
this.isPaused = false;
|
||||||
|
this.showPauseOverlay = false;
|
||||||
|
|
||||||
|
// Fokus zurück auf Canvas setzen
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.canvas) {
|
||||||
|
this.canvas.focus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
resetTaxiPosition() {
|
||||||
|
// Taxi in der Mitte des Screens platzieren
|
||||||
|
this.taxi.x = 200 - this.taxi.width/2;
|
||||||
|
this.taxi.y = 200 - this.taxi.height/2;
|
||||||
|
this.taxi.speed = 0;
|
||||||
|
this.taxi.angle = 0;
|
||||||
|
|
||||||
|
// Aktuelle Tile-Position zurücksetzen
|
||||||
|
this.currentTile.row = 0;
|
||||||
|
this.currentTile.col = 0;
|
||||||
|
},
|
||||||
|
|
||||||
isTaxiOnRoad() {
|
isTaxiOnRoad() {
|
||||||
const tileSize = this.tiles.size;
|
|
||||||
const cols = 8;
|
|
||||||
const rows = 8;
|
|
||||||
|
|
||||||
// Bestimme welches Tile das Taxi gerade belegt
|
|
||||||
const tileCol = Math.floor(this.taxi.x / tileSize);
|
|
||||||
const tileRow = Math.floor(this.taxi.y / tileSize);
|
|
||||||
|
|
||||||
// Prüfe ob das Taxi innerhalb der Canvas-Grenzen ist
|
// Prüfe ob das Taxi innerhalb der Canvas-Grenzen ist
|
||||||
if (tileCol < 0 || tileCol >= cols || tileRow < 0 || tileRow >= rows) {
|
if (this.taxi.x < 0 || this.taxi.x >= this.canvas.width ||
|
||||||
|
this.taxi.y < 0 || this.taxi.y >= this.canvas.height) {
|
||||||
|
if (this.taxi.speed > 0) {
|
||||||
|
console.log('Taxi außerhalb Canvas-Grenzen:', { x: this.taxi.x, y: this.taxi.y });
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bestimme Tile-Typ
|
|
||||||
const tileType = this.getTileType(tileRow, tileCol, rows, cols);
|
|
||||||
|
|
||||||
// Konvertiere Taxi-Position zu relativen Koordinaten innerhalb des Tiles
|
// Hole das aktuelle Tile und dessen Polygone
|
||||||
const relativeX = (this.taxi.x - tileCol * tileSize) / tileSize;
|
const tileType = this.getCurrentTileType();
|
||||||
const relativeY = (this.taxi.y - tileRow * tileSize) / tileSize;
|
const streetTileType = this.mapTileTypeToStreetCoordinates(tileType);
|
||||||
|
const originalTileSize = streetCoordinates.getOriginalTileSize(); // 640px
|
||||||
|
const currentTileSize = 400; // Aktuelle Render-Größe
|
||||||
|
|
||||||
// Prüfe ob das Taxi auf der Straße ist
|
// Hole die Polygon-Koordinaten für dieses Tile
|
||||||
return streetCoordinates.isPointDriveable(relativeX, relativeY, tileType, 1);
|
const regions = streetCoordinates.getDriveableRegions(streetTileType, originalTileSize);
|
||||||
|
|
||||||
|
if (regions.length === 0) {
|
||||||
|
// Keine Polygone definiert = befahrbar
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erstelle Taxi-Rechteck in relativen Koordinaten (0-1)
|
||||||
|
const taxiRect = {
|
||||||
|
x: this.taxi.x / currentTileSize,
|
||||||
|
y: this.taxi.y / currentTileSize,
|
||||||
|
width: this.taxi.width / currentTileSize,
|
||||||
|
height: this.taxi.height / currentTileSize
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Prüfe Kollision mit jedem Polygon
|
||||||
|
for (let i = 0; i < regions.length; i++) {
|
||||||
|
const region = regions[i];
|
||||||
|
|
||||||
|
if (this.rectPolygonCollision(taxiRect, region)) {
|
||||||
|
if (this.taxi.speed > 0) {
|
||||||
|
console.log(`🚨 KOLLISION mit Polygon ${i}!`);
|
||||||
|
}
|
||||||
|
return false; // Kollision = nicht befahrbar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // Keine Kollision = befahrbar
|
||||||
|
},
|
||||||
|
|
||||||
|
// Prüft Kollision zwischen Rechteck und Polygon
|
||||||
|
rectPolygonCollision(rect, polygon) {
|
||||||
|
// Konvertiere Polygon-Koordinaten von absoluten Pixeln zu relativen (0-1)
|
||||||
|
const relativePolygon = polygon.map(point => ({
|
||||||
|
x: point.x / 640, // originalTileSize
|
||||||
|
y: point.y / 640
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Prüfe ob eine der Rechteck-Ecken im Polygon liegt
|
||||||
|
const corners = [
|
||||||
|
{ x: rect.x, y: rect.y }, // Oben links
|
||||||
|
{ x: rect.x + rect.width, y: rect.y }, // Oben rechts
|
||||||
|
{ x: rect.x, y: rect.y + rect.height }, // Unten links
|
||||||
|
{ x: rect.x + rect.width, y: rect.y + rect.height } // Unten rechts
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let i = 0; i < corners.length; i++) {
|
||||||
|
const corner = corners[i];
|
||||||
|
const isInside = this.isPointInPolygon(corner.x, corner.y, relativePolygon);
|
||||||
|
|
||||||
|
if (isInside) {
|
||||||
|
if (this.taxi.speed > 0) {
|
||||||
|
console.log(`🚨 Ecke ${i} ist im Polygon!`);
|
||||||
|
}
|
||||||
|
return true; // Rechteck-Ecke ist im Polygon = Kollision
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prüfe ob eine Polygon-Ecke im Rechteck liegt
|
||||||
|
for (let i = 0; i < relativePolygon.length; i++) {
|
||||||
|
const point = relativePolygon[i];
|
||||||
|
const isInside = this.isPointInRect(point.x, point.y, rect);
|
||||||
|
|
||||||
|
if (isInside) {
|
||||||
|
if (this.taxi.speed > 0) {
|
||||||
|
console.log(`🚨 Polygon-Punkt ${i} ist im Rechteck!`);
|
||||||
|
}
|
||||||
|
return true; // Polygon-Ecke ist im Rechteck = Kollision
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prüfe ob Rechteck-Kanten das Polygon schneiden
|
||||||
|
const rectEdges = [
|
||||||
|
{ x1: rect.x, y1: rect.y, x2: rect.x + rect.width, y2: rect.y }, // Oben
|
||||||
|
{ x1: rect.x + rect.width, y1: rect.y, x2: rect.x + rect.width, y2: rect.y + rect.height }, // Rechts
|
||||||
|
{ x1: rect.x, y1: rect.y + rect.height, x2: rect.x + rect.width, y2: rect.y + rect.height }, // Unten
|
||||||
|
{ x1: rect.x, y1: rect.y, x2: rect.x, y2: rect.y + rect.height } // Links
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const edge of rectEdges) {
|
||||||
|
for (let i = 0; i < relativePolygon.length; i++) {
|
||||||
|
const j = (i + 1) % relativePolygon.length;
|
||||||
|
const polyEdge = {
|
||||||
|
x1: relativePolygon[i].x,
|
||||||
|
y1: relativePolygon[i].y,
|
||||||
|
x2: relativePolygon[j].x,
|
||||||
|
y2: relativePolygon[j].y
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.lineIntersection(edge, polyEdge)) {
|
||||||
|
return true; // Kanten schneiden sich = Kollision
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // Keine Kollision
|
||||||
|
},
|
||||||
|
|
||||||
|
// Prüft ob ein Punkt in einem Polygon liegt (Point-in-Polygon)
|
||||||
|
isPointInPolygon(x, y, polygon) {
|
||||||
|
let inside = false;
|
||||||
|
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
||||||
|
if (((polygon[i].y > y) !== (polygon[j].y > y)) &&
|
||||||
|
(x < (polygon[j].x - polygon[i].x) * (y - polygon[i].y) / (polygon[j].y - polygon[i].y) + polygon[i].x)) {
|
||||||
|
inside = !inside;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inside;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Prüft ob ein Punkt in einem Rechteck liegt
|
||||||
|
isPointInRect(x, y, rect) {
|
||||||
|
return x >= rect.x && x <= rect.x + rect.width &&
|
||||||
|
y >= rect.y && y <= rect.y + rect.height;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Prüft ob zwei Linien sich schneiden
|
||||||
|
lineIntersection(line1, line2) {
|
||||||
|
const x1 = line1.x1, y1 = line1.y1, x2 = line1.x2, y2 = line1.y2;
|
||||||
|
const x3 = line2.x1, y3 = line2.y1, x4 = line2.x2, y4 = line2.y2;
|
||||||
|
|
||||||
|
const denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
|
||||||
|
if (Math.abs(denom) < 1e-10) return false; // Parallele Linien
|
||||||
|
|
||||||
|
const t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom;
|
||||||
|
const u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denom;
|
||||||
|
|
||||||
|
return t >= 0 && t <= 1 && u >= 0 && u <= 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
getCurrentTileType() {
|
||||||
|
// Hole das aktuelle Tile aus der geladenen Map
|
||||||
|
if (this.currentMap && this.currentMap.mapData) {
|
||||||
|
const mapData = this.currentMap.mapData;
|
||||||
|
const tile = mapData[this.currentTile.row] && mapData[this.currentTile.row][this.currentTile.col];
|
||||||
|
|
||||||
|
// Prüfe ob tile ein String ist (direkter Tile-Name) oder ein Objekt mit type-Eigenschaft
|
||||||
|
if (tile) {
|
||||||
|
if (typeof tile === 'string') {
|
||||||
|
return tile;
|
||||||
|
} else if (tile.type) {
|
||||||
|
return tile.type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: Standard-Tile
|
||||||
|
return 'cornertopleft';
|
||||||
},
|
},
|
||||||
|
|
||||||
checkCollision(rect1, rect2) {
|
checkCollision(rect1, rect2) {
|
||||||
@@ -577,7 +810,7 @@ export default {
|
|||||||
|
|
||||||
if (this.taxi.image) {
|
if (this.taxi.image) {
|
||||||
// Zeichne Taxi-Bild
|
// Zeichne Taxi-Bild
|
||||||
console.log('Zeichne Taxi-Bild:', this.taxi.image, 'Position:', this.taxi.x, this.taxi.y);
|
// console.log('Zeichne Taxi-Bild:', this.taxi.image, 'Position:', this.taxi.x, this.taxi.y);
|
||||||
this.ctx.drawImage(
|
this.ctx.drawImage(
|
||||||
this.taxi.image,
|
this.taxi.image,
|
||||||
-this.taxi.width/2,
|
-this.taxi.width/2,
|
||||||
@@ -587,7 +820,7 @@ export default {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Fallback: Zeichne blaues Rechteck wenn Bild nicht geladen
|
// Fallback: Zeichne blaues Rechteck wenn Bild nicht geladen
|
||||||
console.log('Taxi-Bild nicht geladen, zeichne Fallback-Rechteck');
|
// console.log('Taxi-Bild nicht geladen, zeichne Fallback-Rechteck');
|
||||||
this.ctx.fillStyle = '#2196F3';
|
this.ctx.fillStyle = '#2196F3';
|
||||||
this.ctx.fillRect(-this.taxi.width/2, -this.taxi.height/2, this.taxi.width, this.taxi.height);
|
this.ctx.fillRect(-this.taxi.width/2, -this.taxi.height/2, this.taxi.width, this.taxi.height);
|
||||||
}
|
}
|
||||||
@@ -610,8 +843,11 @@ export default {
|
|||||||
|
|
||||||
const tileType = mapData[this.currentTile.row][this.currentTile.col];
|
const tileType = mapData[this.currentTile.row][this.currentTile.col];
|
||||||
if (tileType) {
|
if (tileType) {
|
||||||
|
// Konvertiere Tile-Typ zu streetCoordinates.json Format
|
||||||
|
const streetTileType = this.mapTileTypeToStreetCoordinates(tileType);
|
||||||
|
|
||||||
// Zeichne Straßenregionen für das aktuelle Tile
|
// Zeichne Straßenregionen für das aktuelle Tile
|
||||||
streetCoordinates.drawDriveableRegions(this.ctx, tileType, tileSize, 0, 0);
|
streetCoordinates.drawDriveableRegions(this.ctx, streetTileType, tileSize, 0, 0);
|
||||||
|
|
||||||
// Zeichne Tile-Overlay falls verfügbar
|
// Zeichne Tile-Overlay falls verfügbar
|
||||||
if (this.tiles.images[tileType]) {
|
if (this.tiles.images[tileType]) {
|
||||||
@@ -622,9 +858,10 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
// Fallback: Zeichne Standard-Tile wenn keine Map geladen ist
|
// Fallback: Zeichne Standard-Tile wenn keine Map geladen ist
|
||||||
const tileType = 'cornertopleft'; // Standard-Tile
|
const tileType = 'cornertopleft'; // Standard-Tile
|
||||||
|
const streetTileType = this.mapTileTypeToStreetCoordinates(tileType);
|
||||||
|
|
||||||
// Zeichne Straßenregionen
|
// Zeichne Straßenregionen
|
||||||
streetCoordinates.drawDriveableRegions(this.ctx, tileType, tileSize, 0, 0);
|
streetCoordinates.drawDriveableRegions(this.ctx, streetTileType, tileSize, 0, 0);
|
||||||
|
|
||||||
// Zeichne Tile-Overlay falls verfügbar
|
// Zeichne Tile-Overlay falls verfügbar
|
||||||
if (this.tiles.images[tileType]) {
|
if (this.tiles.images[tileType]) {
|
||||||
@@ -670,6 +907,7 @@ export default {
|
|||||||
|
|
||||||
togglePause() {
|
togglePause() {
|
||||||
this.isPaused = !this.isPaused;
|
this.isPaused = !this.isPaused;
|
||||||
|
this.showPauseOverlay = this.isPaused;
|
||||||
},
|
},
|
||||||
|
|
||||||
restartLevel() {
|
restartLevel() {
|
||||||
@@ -726,7 +964,7 @@ export default {
|
|||||||
loadTaxiImage() {
|
loadTaxiImage() {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
console.log('Taxi-Bild erfolgreich geladen:', img);
|
// console.log('Taxi-Bild erfolgreich geladen:', img);
|
||||||
this.taxi.image = img;
|
this.taxi.image = img;
|
||||||
};
|
};
|
||||||
img.onerror = (error) => {
|
img.onerror = (error) => {
|
||||||
@@ -734,7 +972,7 @@ export default {
|
|||||||
console.log('Versuche Pfad:', '/images/taxi/taxi.svg');
|
console.log('Versuche Pfad:', '/images/taxi/taxi.svg');
|
||||||
};
|
};
|
||||||
img.src = '/images/taxi/taxi.svg';
|
img.src = '/images/taxi/taxi.svg';
|
||||||
console.log('Lade Taxi-Bild von:', '/images/taxi/taxi.svg');
|
// console.log('Lade Taxi-Bild von:', '/images/taxi/taxi.svg');
|
||||||
},
|
},
|
||||||
|
|
||||||
async loadMaps() {
|
async loadMaps() {
|
||||||
@@ -745,8 +983,8 @@ export default {
|
|||||||
// Verwende die erste verfügbare Map als Standard
|
// Verwende die erste verfügbare Map als Standard
|
||||||
if (this.maps.length > 0) {
|
if (this.maps.length > 0) {
|
||||||
this.currentMap = this.maps[0];
|
this.currentMap = this.maps[0];
|
||||||
|
this.selectedMap = this.maps[0]; // Auch selectedMap setzen
|
||||||
this.selectedMapId = this.maps[0].id;
|
this.selectedMapId = this.maps[0].id;
|
||||||
console.log('Geladene Map:', this.currentMap);
|
|
||||||
|
|
||||||
// Canvas-Größe an geladene Map anpassen
|
// Canvas-Größe an geladene Map anpassen
|
||||||
this.updateCanvasSize();
|
this.updateCanvasSize();
|
||||||
@@ -766,7 +1004,7 @@ export default {
|
|||||||
const selectedMap = this.maps.find(map => map.id === this.selectedMapId);
|
const selectedMap = this.maps.find(map => map.id === this.selectedMapId);
|
||||||
if (selectedMap) {
|
if (selectedMap) {
|
||||||
this.currentMap = selectedMap;
|
this.currentMap = selectedMap;
|
||||||
console.log('Gewechselt zu Map:', selectedMap);
|
// console.log('Gewechselt zu Map:', selectedMap);
|
||||||
|
|
||||||
// Canvas-Größe an neue Map anpassen
|
// Canvas-Größe an neue Map anpassen
|
||||||
this.updateCanvasSize();
|
this.updateCanvasSize();
|
||||||
|
|||||||
Reference in New Issue
Block a user