Änderung: Erweiterung der Logik zur Überprüfung von Rotlichtverstößen im Taxi-Spiel
Änderungen: - Hinzufügung von Variablen zur Speicherung der letzten Position des Taxis und zur Verwaltung von Rotlichtverstößen. - Implementierung einer neuen Methode `checkRedLightViolation`, die überprüft, ob das Taxi bei Rotlicht über die Haltelinie fährt. - Anpassung der Minimap-Zeichnung, um die Leistung durch Drosselung der Zeichenintervalle zu verbessern. - Verbesserung der Logik zur Darstellung von Ampeln und deren Phasen. Diese Anpassungen erhöhen die Realitätsnähe und die Spielmechanik im Taxi-Minispiel, indem sie eine präzisere Verkehrsüberwachung ermöglichen.
This commit is contained in:
@@ -243,6 +243,9 @@ export default {
|
||||
trafficLightStates: {},
|
||||
lastTrafficLightTick: 0,
|
||||
redLightViolations: 0,
|
||||
redLightLastCount: {},
|
||||
lastMinimapDraw: 0,
|
||||
minimapDrawInterval: 120,
|
||||
maps: [], // Geladene Maps aus der Datenbank
|
||||
currentMap: null, // Aktuell verwendete Map
|
||||
selectedMapId: null, // ID der ausgewählten Map
|
||||
@@ -256,6 +259,8 @@ export default {
|
||||
selectedStreetName: null
|
||||
,motorStopTimeout: null
|
||||
,houseNumbers: {}
|
||||
,prevTaxiX: 250
|
||||
,prevTaxiY: 250
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -728,8 +733,12 @@ export default {
|
||||
this.checkCollisions();
|
||||
this.render();
|
||||
|
||||
// Minimap zeichnen
|
||||
this.drawMinimap();
|
||||
// Minimap zeichnen (gedrosselt)
|
||||
const nowTs = Date.now();
|
||||
if (nowTs - this.lastMinimapDraw >= this.minimapDrawInterval) {
|
||||
this.drawMinimap();
|
||||
this.lastMinimapDraw = nowTs;
|
||||
}
|
||||
|
||||
this.gameLoop = requestAnimationFrame(this.update);
|
||||
},
|
||||
@@ -784,6 +793,9 @@ export default {
|
||||
this.lastSteerChange = currentTime;
|
||||
}
|
||||
|
||||
// Vorherige Position merken für Richtungs-/Grenzprüfungen
|
||||
this.prevTaxiX = this.taxi.x;
|
||||
this.prevTaxiY = this.taxi.y;
|
||||
// Aktualisiere Position (+20% Geschwindigkeit)
|
||||
this.taxi.x += Math.cos(this.taxi.angle) * this.taxi.speed * 0.12;
|
||||
this.taxi.y += Math.sin(this.taxi.angle) * this.taxi.speed * 0.12;
|
||||
@@ -860,6 +872,10 @@ export default {
|
||||
if (!this.isPaused && !this.isTaxiOnRoad()) {
|
||||
this.handleCrash();
|
||||
}
|
||||
// Rotlichtverstöße prüfen
|
||||
if (!this.isPaused) {
|
||||
this.checkRedLightViolation();
|
||||
}
|
||||
|
||||
// Prüfe Hindernisse nur wenn das Spiel nicht pausiert ist
|
||||
if (!this.isPaused) {
|
||||
@@ -870,6 +886,84 @@ export default {
|
||||
});
|
||||
}
|
||||
},
|
||||
// Prüft Überfahren der (virtuell verdoppelten) Haltelinie aus der straßenzugewandten Seite
|
||||
checkRedLightViolation() {
|
||||
if (!this.currentMap || !this.currentMap.mapData) return;
|
||||
const tileSize = this.tiles.size;
|
||||
const tileType = this.getCurrentTileType();
|
||||
const approaches = this.getTileApproaches(tileType);
|
||||
if (!approaches.top && !approaches.right && !approaches.bottom && !approaches.left) return;
|
||||
if (!this.getTrafficLightFor(this.currentTile.col + (this.currentMap.offsetX||0), this.currentTile.row + (this.currentMap.offsetY||0))) return;
|
||||
|
||||
const phase = this.getTrafficLightPhase(this.currentTile.col + (this.currentMap.offsetX||0), this.currentTile.row + (this.currentMap.offsetY||0));
|
||||
const rects = this.getVirtualStopLineRects(tileSize, approaches);
|
||||
|
||||
// Einseitige Prüfung je Richtung und Phasen-Logik
|
||||
// Zu prüfende Ecken laut Vorgabe:
|
||||
// Horizontal: links unten (BL) und rechts oben (TR) müssen rot sein, um Verstoß zu zählen
|
||||
// Vertikal: rechts unten (BR) und links oben (TL) müssen rot sein
|
||||
// Diagonale Synchronisierung: TL/BR sind vertikal gekoppelt, TR/BL horizontal
|
||||
const isHorRed = (phase === 2 || phase === 3);
|
||||
const isVerRed = (phase === 0 || phase === 1);
|
||||
|
||||
let violated = false;
|
||||
|
||||
// Von welcher Seite kommt das Taxi? Delta der Mittelpunkt-Position
|
||||
const prevCX = this.prevTaxiX + this.taxi.width / 2;
|
||||
const prevCY = this.prevTaxiY + this.taxi.height / 2;
|
||||
const currCX = this.taxi.x + this.taxi.width / 2;
|
||||
const currCY = this.taxi.y + this.taxi.height / 2;
|
||||
const vx = currCX - prevCX;
|
||||
const vy = currCY - prevCY;
|
||||
|
||||
// Top-Band: von oben nach unten (prev oben, curr unten), Eintritt über obere Bandkante y0
|
||||
if (rects.top && approaches.top) {
|
||||
const x0 = rects.top.x, x1 = rects.top.x + rects.top.width;
|
||||
const y0 = rects.top.y, y1 = rects.top.y + rects.top.height;
|
||||
const inX = (prevCX >= x0 && prevCX <= x1) || (currCX >= x0 && currCX <= x1);
|
||||
if (vy > 0 && inX && prevCY < y0 && currCY >= y0) {
|
||||
if (isVerRed) violated = true;
|
||||
}
|
||||
}
|
||||
// Bottom-Band: von unten nach oben (prev unten, curr oben), Eintritt über untere Bandkante y1
|
||||
if (rects.bottom && approaches.bottom) {
|
||||
const x0 = rects.bottom.x, x1 = rects.bottom.x + rects.bottom.width;
|
||||
const y0 = rects.bottom.y, y1 = rects.bottom.y + rects.bottom.height;
|
||||
const inX = (prevCX >= x0 && prevCX <= x1) || (currCX >= x0 && currCX <= x1);
|
||||
if (vy < 0 && inX && prevCY > y1 && currCY <= y1) {
|
||||
if (isVerRed) violated = true;
|
||||
}
|
||||
}
|
||||
// Left-Band: von links nach rechts (prev links, curr rechts), Eintritt über linke Bandkante x0
|
||||
if (rects.left && approaches.left) {
|
||||
const x0 = rects.left.x, x1 = rects.left.x + rects.left.width;
|
||||
const y0 = rects.left.y, y1 = rects.left.y + rects.left.height;
|
||||
const inY = (prevCY >= y0 && prevCY <= y1) || (currCY >= y0 && currCY <= y1);
|
||||
if (vx > 0 && inY && prevCX < x0 && currCX >= x0) {
|
||||
if (isHorRed) violated = true;
|
||||
}
|
||||
}
|
||||
// Right-Band: von rechts nach links (prev rechts, curr links), Eintritt über rechte Bandkante x1
|
||||
if (rects.right && approaches.right) {
|
||||
const x0 = rects.right.x, x1 = rects.right.x + rects.right.width;
|
||||
const y0 = rects.right.y, y1 = rects.right.y + rects.right.height;
|
||||
const inY = (prevCY >= y0 && prevCY <= y1) || (currCY >= y0 && currCY <= y1);
|
||||
if (vx < 0 && inY && prevCX > x1 && currCX <= x1) {
|
||||
if (isHorRed) violated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (violated) {
|
||||
// Entprellen: pro Tile nur einmal pro tatsächlichem Übertritt zählen
|
||||
const key = `${this.currentTile.col},${this.currentTile.row}`;
|
||||
const now = Date.now();
|
||||
const last = this.redLightLastCount[key] || 0;
|
||||
if (now - last > 500) { // 0.5s Sperrzeit
|
||||
this.redLightLastCount[key] = now;
|
||||
this.redLightViolations += 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleCrash() {
|
||||
// Verhindere mehrfache Crashes in kurzer Zeit
|
||||
@@ -1239,23 +1333,23 @@ export default {
|
||||
if (hide.TR) showTR = false;
|
||||
if (hide.BL) showBL = false;
|
||||
if (hide.BR) showBR = false;
|
||||
const drawCorner = (corner, x, y) => {
|
||||
let img = imgRed;
|
||||
if (corner === 'top') {
|
||||
if (phase === 0) img = imgGreen; else if (phase === 1) img = imgYellow; else if (phase === 2) img = imgRed; else img = imgRedYellow;
|
||||
} else if (corner === 'bottom') {
|
||||
if (phase === 0) img = imgRed; else if (phase === 1) img = imgRedYellow; else if (phase === 2) img = imgGreen; else img = imgYellow;
|
||||
} else if (corner === 'left') {
|
||||
if (phase === 0) img = imgGreen; else if (phase === 1) img = imgYellow; else if (phase === 2) img = imgRed; else img = imgRedYellow;
|
||||
} else if (corner === 'right') {
|
||||
if (phase === 0) img = imgRed; else if (phase === 1) img = imgRedYellow; else if (phase === 2) img = imgGreen; else img = imgYellow;
|
||||
}
|
||||
if (img && img.complete) this.ctx.drawImage(img, x, y, sTL, sTL);
|
||||
};
|
||||
if (showTL) drawCorner('left', leftX, topY);
|
||||
if (showTR) drawCorner('right', rightX, topY);
|
||||
if (showBL) drawCorner('left', leftX, bottomY);
|
||||
if (showBR) drawCorner('right', rightX, bottomY);
|
||||
const drawByAxis = (axis, x, y) => {
|
||||
// axis: 'H' (horizontal) oder 'V' (vertikal)
|
||||
let img = imgRed;
|
||||
if (axis === 'H') {
|
||||
// Horizontal: Phase 0=grün, 1=gelb, 2=rot, 3=rot-gelb
|
||||
if (phase === 0) img = imgGreen; else if (phase === 1) img = imgYellow; else if (phase === 2) img = imgRed; else img = imgRedYellow;
|
||||
} else {
|
||||
// Vertikal: Gegenphase: 0=rot, 1=rot-gelb, 2=grün, 3=gelb
|
||||
if (phase === 0) img = imgRed; else if (phase === 1) img = imgRedYellow; else if (phase === 2) img = imgGreen; else img = imgYellow;
|
||||
}
|
||||
if (img && img.complete) this.ctx.drawImage(img, x, y, sTL, sTL);
|
||||
};
|
||||
// Diagonale Synchronisation: TL/BR vertikal, TR/BL horizontal
|
||||
if (showTL) drawByAxis('V', leftX, topY);
|
||||
if (showTR) drawByAxis('H', rightX, topY);
|
||||
if (showBL) drawByAxis('H', leftX, bottomY);
|
||||
if (showBR) drawByAxis('V', rightX, bottomY);
|
||||
}
|
||||
}
|
||||
this.drawStreetNamesOnMainCanvas(this.ctx, tileSize, tileType, absCol, absRow);
|
||||
@@ -1395,6 +1489,24 @@ export default {
|
||||
if (approaches.right) ctx.fillRect(size - m, (size - width) / 2 - 30, thickness, width);
|
||||
ctx.restore();
|
||||
},
|
||||
// Liefert die virtuellen (breit verdoppelten) Haltelinienrechtecke pro Seite, ohne zu zeichnen
|
||||
getVirtualStopLineRects(size, approaches = { top:true, right:true, bottom:true, left:true }) {
|
||||
const margin = 120;
|
||||
const extra = 30;
|
||||
const m = margin + extra;
|
||||
const thickness = 5 * 2; // doppelte Breite für Erkennung
|
||||
const width = 60; // Länge der Linie unverändert
|
||||
const rects = {};
|
||||
// Oben
|
||||
if (approaches.top) rects.top = { x: (size - width) / 2 - 30, y: m - thickness, width: width, height: thickness };
|
||||
// Unten
|
||||
if (approaches.bottom) rects.bottom = { x: (size - width) / 2 + 30, y: size - m, width: width, height: thickness };
|
||||
// Links
|
||||
if (approaches.left) rects.left = { x: m - thickness, y: (size - width) / 2 + 30, width: thickness, height: width };
|
||||
// Rechts
|
||||
if (approaches.right) rects.right = { x: size - m, y: (size - width) / 2 - 30, width: thickness, height: width };
|
||||
return rects;
|
||||
},
|
||||
// Liefert, von welchen Seiten eine Straße an dieses Tile anbindet
|
||||
getTileApproaches(tileType) {
|
||||
switch (tileType) {
|
||||
|
||||
Reference in New Issue
Block a user