Ä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: {},
|
trafficLightStates: {},
|
||||||
lastTrafficLightTick: 0,
|
lastTrafficLightTick: 0,
|
||||||
redLightViolations: 0,
|
redLightViolations: 0,
|
||||||
|
redLightLastCount: {},
|
||||||
|
lastMinimapDraw: 0,
|
||||||
|
minimapDrawInterval: 120,
|
||||||
maps: [], // Geladene Maps aus der Datenbank
|
maps: [], // Geladene Maps aus der Datenbank
|
||||||
currentMap: null, // Aktuell verwendete Map
|
currentMap: null, // Aktuell verwendete Map
|
||||||
selectedMapId: null, // ID der ausgewählten Map
|
selectedMapId: null, // ID der ausgewählten Map
|
||||||
@@ -256,6 +259,8 @@ export default {
|
|||||||
selectedStreetName: null
|
selectedStreetName: null
|
||||||
,motorStopTimeout: null
|
,motorStopTimeout: null
|
||||||
,houseNumbers: {}
|
,houseNumbers: {}
|
||||||
|
,prevTaxiX: 250
|
||||||
|
,prevTaxiY: 250
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -728,8 +733,12 @@ export default {
|
|||||||
this.checkCollisions();
|
this.checkCollisions();
|
||||||
this.render();
|
this.render();
|
||||||
|
|
||||||
// Minimap zeichnen
|
// Minimap zeichnen (gedrosselt)
|
||||||
|
const nowTs = Date.now();
|
||||||
|
if (nowTs - this.lastMinimapDraw >= this.minimapDrawInterval) {
|
||||||
this.drawMinimap();
|
this.drawMinimap();
|
||||||
|
this.lastMinimapDraw = nowTs;
|
||||||
|
}
|
||||||
|
|
||||||
this.gameLoop = requestAnimationFrame(this.update);
|
this.gameLoop = requestAnimationFrame(this.update);
|
||||||
},
|
},
|
||||||
@@ -784,6 +793,9 @@ export default {
|
|||||||
this.lastSteerChange = currentTime;
|
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)
|
// Aktualisiere Position (+20% Geschwindigkeit)
|
||||||
this.taxi.x += Math.cos(this.taxi.angle) * this.taxi.speed * 0.12;
|
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;
|
this.taxi.y += Math.sin(this.taxi.angle) * this.taxi.speed * 0.12;
|
||||||
@@ -860,6 +872,10 @@ export default {
|
|||||||
if (!this.isPaused && !this.isTaxiOnRoad()) {
|
if (!this.isPaused && !this.isTaxiOnRoad()) {
|
||||||
this.handleCrash();
|
this.handleCrash();
|
||||||
}
|
}
|
||||||
|
// Rotlichtverstöße prüfen
|
||||||
|
if (!this.isPaused) {
|
||||||
|
this.checkRedLightViolation();
|
||||||
|
}
|
||||||
|
|
||||||
// Prüfe Hindernisse nur wenn das Spiel nicht pausiert ist
|
// Prüfe Hindernisse nur wenn das Spiel nicht pausiert ist
|
||||||
if (!this.isPaused) {
|
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() {
|
handleCrash() {
|
||||||
// Verhindere mehrfache Crashes in kurzer Zeit
|
// Verhindere mehrfache Crashes in kurzer Zeit
|
||||||
@@ -1239,23 +1333,23 @@ export default {
|
|||||||
if (hide.TR) showTR = false;
|
if (hide.TR) showTR = false;
|
||||||
if (hide.BL) showBL = false;
|
if (hide.BL) showBL = false;
|
||||||
if (hide.BR) showBR = false;
|
if (hide.BR) showBR = false;
|
||||||
const drawCorner = (corner, x, y) => {
|
const drawByAxis = (axis, x, y) => {
|
||||||
|
// axis: 'H' (horizontal) oder 'V' (vertikal)
|
||||||
let img = imgRed;
|
let img = imgRed;
|
||||||
if (corner === 'top') {
|
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;
|
if (phase === 0) img = imgGreen; else if (phase === 1) img = imgYellow; else if (phase === 2) img = imgRed; else img = imgRedYellow;
|
||||||
} else if (corner === 'bottom') {
|
} else {
|
||||||
if (phase === 0) img = imgRed; else if (phase === 1) img = imgRedYellow; else if (phase === 2) img = imgGreen; else img = imgYellow;
|
// Vertikal: Gegenphase: 0=rot, 1=rot-gelb, 2=grün, 3=gelb
|
||||||
} 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 (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 (img && img.complete) this.ctx.drawImage(img, x, y, sTL, sTL);
|
||||||
};
|
};
|
||||||
if (showTL) drawCorner('left', leftX, topY);
|
// Diagonale Synchronisation: TL/BR vertikal, TR/BL horizontal
|
||||||
if (showTR) drawCorner('right', rightX, topY);
|
if (showTL) drawByAxis('V', leftX, topY);
|
||||||
if (showBL) drawCorner('left', leftX, bottomY);
|
if (showTR) drawByAxis('H', rightX, topY);
|
||||||
if (showBR) drawCorner('right', rightX, bottomY);
|
if (showBL) drawByAxis('H', leftX, bottomY);
|
||||||
|
if (showBR) drawByAxis('V', rightX, bottomY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.drawStreetNamesOnMainCanvas(this.ctx, tileSize, tileType, absCol, absRow);
|
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);
|
if (approaches.right) ctx.fillRect(size - m, (size - width) / 2 - 30, thickness, width);
|
||||||
ctx.restore();
|
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
|
// Liefert, von welchen Seiten eine Straße an dieses Tile anbindet
|
||||||
getTileApproaches(tileType) {
|
getTileApproaches(tileType) {
|
||||||
switch (tileType) {
|
switch (tileType) {
|
||||||
|
|||||||
Reference in New Issue
Block a user