Erweiterung der Fahrzeug-Logik und Anpassung der Abbiege- sowie Spawn-Mechanik im Taxi-Spiel
Änderungen: - Erhöhung des Toleranzfensters für die Abbiegeerkennung, um die Fahrzeugbewegung zu verbessern. - Implementierung einer neuen Logik für T-Kreuzungen, die das Abbiegen von Fahrzeugen steuert. - Anpassung der erlaubten Spawn-Richtungen, um das Spawn-Verhalten zu optimieren und das Fahren nach unten zu verhindern. - Strikter Zwang für Fahrzeuge, die von oben kommen, um nicht geradeaus weiterzufahren. Diese Anpassungen verbessern die Interaktion der Fahrzeuge und optimieren die Spielmechanik durch präzisere Abbiege- und Spawn-Logik.
This commit is contained in:
@@ -467,7 +467,7 @@ export default {
|
|||||||
const tileType = this.mapTileTypeToStreetCoordinates(this.getCurrentTileType());
|
const tileType = this.mapTileTypeToStreetCoordinates(this.getCurrentTileType());
|
||||||
|
|
||||||
// Toleranzfenster um die Mittellinien, damit der Trigger nicht frame-genau sein muss
|
// Toleranzfenster um die Mittellinien, damit der Trigger nicht frame-genau sein muss
|
||||||
const tol = 0.01; // ~5px bei 500px Tilegröße
|
const tol = 0.03; // ~15px bei 500px Tilegröße – breitere Toleranz
|
||||||
const nearYCenter = ry > 0.5 - tol && ry < 0.5 + tol;
|
const nearYCenter = ry > 0.5 - tol && ry < 0.5 + tol;
|
||||||
const nearXCenter = rx > 0.5 - tol && rx < 0.5 + tol;
|
const nearXCenter = rx > 0.5 - tol && rx < 0.5 + tol;
|
||||||
|
|
||||||
@@ -492,6 +492,29 @@ export default {
|
|||||||
if (car.direction === 'down' && nearYCenter) return 'left';
|
if (car.direction === 'down' && nearYCenter) return 'left';
|
||||||
if (car.direction === 'right' && nearXCenter) return 'up';
|
if (car.direction === 'right' && nearXCenter) return 'up';
|
||||||
return null;
|
return null;
|
||||||
|
case 'tdown': {
|
||||||
|
// T-Kreuzung: unten, links, rechts offen; oben verboten
|
||||||
|
if (!(nearXCenter || nearYCenter)) {
|
||||||
|
// Sonderfall: Von oben kommend früher zwingen, bevor die Mitte exakt erreicht ist
|
||||||
|
if (car.direction === 'up' && ry <= 0.5 + tol) {
|
||||||
|
return Math.random() < 0.5 ? 'left' : 'right';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const choices = [];
|
||||||
|
if (car.direction === 'down') {
|
||||||
|
// Von oben kommend: NICHT weiter nach unten fahren
|
||||||
|
choices.push('left', 'right');
|
||||||
|
} else if (car.direction === 'left' || car.direction === 'right') {
|
||||||
|
// Geradeaus erlaubt (links/rechts), außerdem nach unten
|
||||||
|
choices.push(car.direction, 'down');
|
||||||
|
} else if (car.direction === 'up') {
|
||||||
|
// Von oben: nur links oder rechts, niemals weiter nach oben
|
||||||
|
choices.push('left', 'right');
|
||||||
|
}
|
||||||
|
if (choices.length === 0) return null;
|
||||||
|
return choices[Math.floor(Math.random() * choices.length)];
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// Kreuzung: bei Zentrumslinien abbiegen erlaubt – Richtung später wählen
|
// Kreuzung: bei Zentrumslinien abbiegen erlaubt – Richtung später wählen
|
||||||
if (nearXCenter || nearYCenter) return this.getRandomTargetDirection(car.direction);
|
if (nearXCenter || nearYCenter) return this.getRandomTargetDirection(car.direction);
|
||||||
@@ -698,6 +721,10 @@ export default {
|
|||||||
if (moved) {
|
if (moved) {
|
||||||
this.currentTile.row = newRow;
|
this.currentTile.row = newRow;
|
||||||
this.currentTile.col = newCol;
|
this.currentTile.col = newCol;
|
||||||
|
|
||||||
|
// Entferne alle Autos vom alten Tile
|
||||||
|
this.cars = [];
|
||||||
|
|
||||||
// Nach Tile-Wechsel: eine Frame lang Rotlicht-Prüfung aussetzen
|
// Nach Tile-Wechsel: eine Frame lang Rotlicht-Prüfung aussetzen
|
||||||
// und prev-Position auf aktuelle setzen, um false positives zu vermeiden
|
// und prev-Position auf aktuelle setzen, um false positives zu vermeiden
|
||||||
this.prevTaxiX = this.taxi.x;
|
this.prevTaxiX = this.taxi.x;
|
||||||
@@ -1472,7 +1499,14 @@ export default {
|
|||||||
lastPosition: { x: spawnPosition.x, y: spawnPosition.y }, // Letzte Position für Bewegung
|
lastPosition: { x: spawnPosition.x, y: spawnPosition.y }, // Letzte Position für Bewegung
|
||||||
hasTurnedAtIntersection: false, // Flag um mehrfaches Abbiegen zu verhindern
|
hasTurnedAtIntersection: false, // Flag um mehrfaches Abbiegen zu verhindern
|
||||||
targetDirection: null, // Zielrichtung an der Kreuzung (wird beim Tile-Betreten festgelegt)
|
targetDirection: null, // Zielrichtung an der Kreuzung (wird beim Tile-Betreten festgelegt)
|
||||||
targetLane: null // Zielspur basierend auf Zielrichtung
|
targetLane: null, // Zielspur basierend auf Zielrichtung
|
||||||
|
laneAxis: spawnPosition.laneAxis,
|
||||||
|
laneCoord: spawnPosition.laneCoord,
|
||||||
|
willTurn: spawnPosition.willTurn,
|
||||||
|
turnDirection: spawnPosition.turnDirection,
|
||||||
|
turnX: spawnPosition.turnX,
|
||||||
|
turnY: spawnPosition.turnY,
|
||||||
|
turnAngle: spawnPosition.turnAngle
|
||||||
};
|
};
|
||||||
|
|
||||||
this.cars.push(car);
|
this.cars.push(car);
|
||||||
@@ -1486,13 +1520,13 @@ export default {
|
|||||||
// Basierend auf der tile-Struktur und welche Seiten offen sind
|
// Basierend auf der tile-Struktur und welche Seiten offen sind
|
||||||
switch (tileType) {
|
switch (tileType) {
|
||||||
case 'cornertopleft':
|
case 'cornertopleft':
|
||||||
return ['left', 'up']; // Bewegt sich nach links (von rechts spawnen) und nach oben (von unten spawnen)
|
return ['right', 'down']; // Kommt von links (bewegt sich nach rechts) und von oben (bewegt sich nach unten)
|
||||||
case 'cornertopright':
|
case 'cornertopright':
|
||||||
return ['right', 'up']; // Bewegt sich nach rechts (von links spawnen) und nach oben (von unten spawnen)
|
return ['left', 'down']; // Kommt von rechts (bewegt sich nach links) und von oben (bewegt sich nach unten)
|
||||||
case 'cornerbottomleft':
|
case 'cornerbottomleft':
|
||||||
return ['left', 'down']; // Bewegt sich nach links (von rechts spawnen) und nach unten (von oben spawnen)
|
return ['right', 'up']; // Kommt von links (bewegt sich nach rechts) und von unten (bewegt sich nach oben)
|
||||||
case 'cornerbottomright':
|
case 'cornerbottomright':
|
||||||
return ['left', 'up']; // Bewegt sich nach links (von rechts spawnen) und nach oben (von unten spawnen)
|
return ['left', 'up']; // Kommt von rechts (bewegt sich nach links) und von unten (bewegt sich nach oben)
|
||||||
case 'horizontal':
|
case 'horizontal':
|
||||||
case 'fuelhorizontal':
|
case 'fuelhorizontal':
|
||||||
return ['left', 'right']; // Bewegt sich nach links (von rechts spawnen) und nach rechts (von links spawnen)
|
return ['left', 'right']; // Bewegt sich nach links (von rechts spawnen) und nach rechts (von links spawnen)
|
||||||
@@ -1504,16 +1538,190 @@ export default {
|
|||||||
case 'tup':
|
case 'tup':
|
||||||
return ['up', 'left', 'right']; // Bewegt sich nach oben, links und rechts
|
return ['up', 'left', 'right']; // Bewegt sich nach oben, links und rechts
|
||||||
case 'tdown':
|
case 'tdown':
|
||||||
return ['down', 'left', 'right']; // Bewegt sich nach unten, links und rechts
|
return ['up', 'left', 'right']; // Fahrzeuge kommen von unten/links/rechts (nicht von oben)
|
||||||
case 'tleft':
|
case 'tleft':
|
||||||
return ['left', 'up', 'down']; // Bewegt sich nach links, oben und unten
|
return ['right', 'up', 'down']; // Kommt von links (bewegt sich nach rechts), von oben (bewegt sich nach unten) und von unten (bewegt sich nach oben)
|
||||||
case 'tright':
|
case 'tright':
|
||||||
return ['right', 'up', 'down']; // Bewegt sich nach rechts, oben und unten
|
return ['left', 'up', 'down']; // Kommt von rechts (bewegt sich nach links), von oben (bewegt sich nach unten) und von unten (bewegt sich nach oben)
|
||||||
default:
|
default:
|
||||||
return []; // Keine erlaubten Spawn-Richtungen
|
return []; // Keine erlaubten Spawn-Richtungen
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Berechnet ob und wo ein Auto abbiegen wird
|
||||||
|
calculateTurnInfo(tileType, direction) {
|
||||||
|
const tileSize = this.tiles.size;
|
||||||
|
|
||||||
|
// Für tdown: Autos müssen abbiegen
|
||||||
|
if (tileType === 'tdown') {
|
||||||
|
if (direction === 'up') {
|
||||||
|
// Kommt von unten, muss nach links oder rechts abbiegen
|
||||||
|
const turnDirection = Math.random() < 0.5 ? 'left' : 'right';
|
||||||
|
const turnX = turnDirection === 'left' ? 0.375 * tileSize : 0.625 * tileSize;
|
||||||
|
const turnY = 0.5 * tileSize; // Mitte des Tiles
|
||||||
|
const turnAngle = turnDirection === 'left' ? Math.PI : 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
willTurn: true,
|
||||||
|
turnDirection: turnDirection,
|
||||||
|
turnX: turnX,
|
||||||
|
turnY: turnY,
|
||||||
|
turnAngle: turnAngle
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Für cornerBottomRight: Verbindet untere und rechte Seite
|
||||||
|
// Kurve von unten nach rechts oder von rechts nach unten
|
||||||
|
if (tileType === 'cornerbottomright') {
|
||||||
|
if (direction === 'left') {
|
||||||
|
// Kommt von rechts (Y-Spur ~212.5px = 0.425), biegt nach unten ab (X-Spur ~212.5px = 0.425)
|
||||||
|
const laneMargin = 0.03;
|
||||||
|
const laneCenter = 0.375 + (0.5 - 0.375) / 2; // Mitte der linken/oberen Spur = 0.4375
|
||||||
|
const turnX = laneCenter * tileSize; // X-Position nach dem Abbiegen
|
||||||
|
const turnY = laneCenter * tileSize; // Y-Position beim Abbiegen
|
||||||
|
const turnAngle = Math.PI / 2; // nach unten
|
||||||
|
|
||||||
|
return {
|
||||||
|
willTurn: true,
|
||||||
|
turnDirection: 'down',
|
||||||
|
turnX: turnX,
|
||||||
|
turnY: turnY,
|
||||||
|
turnAngle: turnAngle
|
||||||
|
};
|
||||||
|
} else if (direction === 'up') {
|
||||||
|
// Kommt von unten (X-Spur ~281px = 0.5625), biegt nach rechts ab (Y-Spur ~281px = 0.5625)
|
||||||
|
const laneCenter = 0.5 + (0.625 - 0.5) / 2; // Mitte der rechten/unteren Spur = 0.5625
|
||||||
|
const turnX = laneCenter * tileSize; // X-Position beim Abbiegen
|
||||||
|
const turnY = laneCenter * tileSize; // Y-Position nach dem Abbiegen
|
||||||
|
const turnAngle = 0; // nach rechts
|
||||||
|
|
||||||
|
return {
|
||||||
|
willTurn: true,
|
||||||
|
turnDirection: 'right',
|
||||||
|
turnX: turnX,
|
||||||
|
turnY: turnY,
|
||||||
|
turnAngle: turnAngle
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Für cornerTopRight: Verbindet obere und rechte Seite
|
||||||
|
// Kurve von oben nach rechts oder von rechts nach oben
|
||||||
|
if (tileType === 'cornertopright') {
|
||||||
|
if (direction === 'left') {
|
||||||
|
// Kommt von rechts (Y-Spur ~212.5px), biegt nach oben ab (X-Spur ~281px)
|
||||||
|
const laneCenterLower = 0.375 + (0.5 - 0.375) / 2; // 0.4375
|
||||||
|
const laneCenterUpper = 0.5 + (0.625 - 0.5) / 2; // 0.5625
|
||||||
|
const turnX = laneCenterUpper * tileSize; // X-Position nach dem Abbiegen
|
||||||
|
const turnY = laneCenterLower * tileSize; // Y-Position beim Abbiegen
|
||||||
|
const turnAngle = -Math.PI / 2; // nach oben
|
||||||
|
|
||||||
|
return {
|
||||||
|
willTurn: true,
|
||||||
|
turnDirection: 'up',
|
||||||
|
turnX: turnX,
|
||||||
|
turnY: turnY,
|
||||||
|
turnAngle: turnAngle
|
||||||
|
};
|
||||||
|
} else if (direction === 'down') {
|
||||||
|
// Kommt von oben (X-Spur ~281px), biegt nach rechts ab (Y-Spur ~281px)
|
||||||
|
const laneCenter = 0.5 + (0.625 - 0.5) / 2; // 0.5625
|
||||||
|
const turnX = laneCenter * tileSize;
|
||||||
|
const turnY = laneCenter * tileSize;
|
||||||
|
const turnAngle = 0; // nach rechts
|
||||||
|
|
||||||
|
return {
|
||||||
|
willTurn: true,
|
||||||
|
turnDirection: 'right',
|
||||||
|
turnX: turnX,
|
||||||
|
turnY: turnY,
|
||||||
|
turnAngle: turnAngle
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Für cornerTopLeft: Verbindet obere und linke Seite
|
||||||
|
// Kurve von oben nach links oder von links nach oben
|
||||||
|
if (tileType === 'cornertopleft') {
|
||||||
|
if (direction === 'right') {
|
||||||
|
// Kommt von links (Y-Spur ~281px), biegt nach oben ab (X-Spur ~281px)
|
||||||
|
const laneCenter = 0.5 + (0.625 - 0.5) / 2; // 0.5625
|
||||||
|
const turnX = laneCenter * tileSize;
|
||||||
|
const turnY = laneCenter * tileSize;
|
||||||
|
const turnAngle = -Math.PI / 2; // nach oben
|
||||||
|
|
||||||
|
return {
|
||||||
|
willTurn: true,
|
||||||
|
turnDirection: 'up',
|
||||||
|
turnX: turnX,
|
||||||
|
turnY: turnY,
|
||||||
|
turnAngle: turnAngle
|
||||||
|
};
|
||||||
|
} else if (direction === 'down') {
|
||||||
|
// Kommt von oben (X-Spur ~212.5px), biegt nach links ab (Y-Spur ~281px)
|
||||||
|
const laneCenterLower = 0.375 + (0.5 - 0.375) / 2; // 0.4375
|
||||||
|
const laneCenterUpper = 0.5 + (0.625 - 0.5) / 2; // 0.5625
|
||||||
|
const turnX = laneCenterLower * tileSize; // X-Position beim Abbiegen
|
||||||
|
const turnY = laneCenterUpper * tileSize; // Y-Position nach dem Abbiegen
|
||||||
|
const turnAngle = Math.PI; // nach links
|
||||||
|
|
||||||
|
return {
|
||||||
|
willTurn: true,
|
||||||
|
turnDirection: 'left',
|
||||||
|
turnX: turnX,
|
||||||
|
turnY: turnY,
|
||||||
|
turnAngle: turnAngle
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Für cornerBottomLeft: Verbindet untere und linke Seite
|
||||||
|
// Kurve von unten nach links oder von links nach unten
|
||||||
|
if (tileType === 'cornerbottomleft') {
|
||||||
|
if (direction === 'right') {
|
||||||
|
// Kommt von links (Y-Spur ~281px), biegt nach unten ab (X-Spur ~212.5px)
|
||||||
|
const laneCenterLower = 0.375 + (0.5 - 0.375) / 2; // 0.4375
|
||||||
|
const laneCenterUpper = 0.5 + (0.625 - 0.5) / 2; // 0.5625
|
||||||
|
const turnX = laneCenterLower * tileSize; // X-Position nach dem Abbiegen
|
||||||
|
const turnY = laneCenterUpper * tileSize; // Y-Position beim Abbiegen
|
||||||
|
const turnAngle = Math.PI / 2; // nach unten
|
||||||
|
|
||||||
|
return {
|
||||||
|
willTurn: true,
|
||||||
|
turnDirection: 'down',
|
||||||
|
turnX: turnX,
|
||||||
|
turnY: turnY,
|
||||||
|
turnAngle: turnAngle
|
||||||
|
};
|
||||||
|
} else if (direction === 'up') {
|
||||||
|
// Kommt von unten (X-Spur ~281px), biegt nach links ab (Y-Spur ~212.5px)
|
||||||
|
const laneCenterLower = 0.375 + (0.5 - 0.375) / 2; // 0.4375
|
||||||
|
const laneCenterUpper = 0.5 + (0.625 - 0.5) / 2; // 0.5625
|
||||||
|
const turnX = laneCenterUpper * tileSize; // X-Position beim Abbiegen
|
||||||
|
const turnY = laneCenterLower * tileSize; // Y-Position nach dem Abbiegen
|
||||||
|
const turnAngle = Math.PI; // nach links
|
||||||
|
|
||||||
|
return {
|
||||||
|
willTurn: true,
|
||||||
|
turnDirection: 'left',
|
||||||
|
turnX: turnX,
|
||||||
|
turnY: turnY,
|
||||||
|
turnAngle: turnAngle
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard: Kein Abbiegen
|
||||||
|
return {
|
||||||
|
willTurn: false,
|
||||||
|
turnDirection: null,
|
||||||
|
turnX: null,
|
||||||
|
turnY: null,
|
||||||
|
turnAngle: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
// Finde eine zufällige befahrbare Spawn-Position für ein Auto
|
// Finde eine zufällige befahrbare Spawn-Position für ein Auto
|
||||||
getRandomCarSpawnPosition() {
|
getRandomCarSpawnPosition() {
|
||||||
if (!this.currentMap || !this.currentMap.tiles) {
|
if (!this.currentMap || !this.currentMap.tiles) {
|
||||||
@@ -1548,26 +1756,35 @@ export default {
|
|||||||
const spawnPositionsMap = {
|
const spawnPositionsMap = {
|
||||||
'right': { relativeX: -0.02, pickRelY: () => 0.5 + laneMargin + Math.random() * (0.625 - 0.5 - 2 * laneMargin), angle: 0, direction: 'right', laneAxis: 'H' },
|
'right': { relativeX: -0.02, pickRelY: () => 0.5 + laneMargin + Math.random() * (0.625 - 0.5 - 2 * laneMargin), angle: 0, direction: 'right', laneAxis: 'H' },
|
||||||
'left': { relativeX: 1.02, pickRelY: () => 0.375 + laneMargin + Math.random() * (0.5 - 0.375 - 2 * laneMargin), angle: Math.PI, direction: 'left', laneAxis: 'H' },
|
'left': { relativeX: 1.02, pickRelY: () => 0.375 + laneMargin + Math.random() * (0.5 - 0.375 - 2 * laneMargin), angle: Math.PI, direction: 'left', laneAxis: 'H' },
|
||||||
'down': { pickRelX: () => 0.375 + laneMargin + Math.random() * (0.5 - 0.375 - 2 * laneMargin), relativeY: -0.02, angle: Math.PI / 2, direction: 'down', laneAxis: 'V' },
|
'up': { pickRelX: () => 0.5 + laneMargin + Math.random() * (0.625 - 0.5 - 2 * laneMargin), relativeY: 1.02, angle: -Math.PI / 2, direction: 'up', laneAxis: 'V' },
|
||||||
'up': { pickRelX: () => 0.5 + laneMargin + Math.random() * (0.625 - 0.5 - 2 * laneMargin), relativeY: 1.02, angle: -Math.PI / 2, direction: 'up', laneAxis: 'V' }
|
'down': { pickRelX: () => 0.375 + laneMargin + Math.random() * (0.5 - 0.375 - 2 * laneMargin), relativeY: -0.02, angle: Math.PI / 2, direction: 'down', laneAxis: 'V' }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wähle eine zufällige erlaubte Richtung
|
// Wähle eine zufällige erlaubte Richtung
|
||||||
const randomDirection = allowedDirections[Math.floor(Math.random() * allowedDirections.length)];
|
const filtered = allowedDirections;
|
||||||
|
const randomDirection = filtered[Math.floor(Math.random() * filtered.length)];
|
||||||
const spawnPos = spawnPositionsMap[randomDirection];
|
const spawnPos = spawnPositionsMap[randomDirection];
|
||||||
|
|
||||||
if (!spawnPos) {
|
if (!spawnPos) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Berechne ob und wo das Auto abbiegen wird
|
||||||
|
const turnInfo = this.calculateTurnInfo(tileType, randomDirection);
|
||||||
|
|
||||||
|
// Alle Autos spawnen außerhalb des Tiles (normale Positionierung)
|
||||||
// Konvertiere relative Koordinaten zu absoluten Pixeln
|
// x und y sind die Mittelpunkte der Spawn-Position
|
||||||
let x = (spawnPos.relativeX != null ? spawnPos.relativeX : (spawnPos.pickRelX ? spawnPos.pickRelX() : 0.5)) * tileSize;
|
let x = (spawnPos.relativeX != null ? spawnPos.relativeX : (spawnPos.pickRelX ? spawnPos.pickRelX() : 0.5)) * tileSize;
|
||||||
let y = (spawnPos.relativeY != null ? spawnPos.relativeY : (spawnPos.pickRelY ? spawnPos.pickRelY() : 0.5)) * tileSize;
|
let y = (spawnPos.relativeY != null ? spawnPos.relativeY : (spawnPos.pickRelY ? spawnPos.pickRelY() : 0.5)) * tileSize;
|
||||||
|
let angle = spawnPos.angle;
|
||||||
|
let laneCoord;
|
||||||
|
|
||||||
|
// Berechne laneCoord basierend auf der Mittelpunkt-Position (BEVOR wir zu linker oberer Ecke konvertieren)
|
||||||
|
// laneCoord ist IMMER die aktuelle Spur-Position auf der Querachse
|
||||||
|
// Beim Abbiegen wird laneCoord später in updateCarMovement aktualisiert
|
||||||
|
laneCoord = spawnPos.laneAxis === 'H' ? y : x;
|
||||||
|
|
||||||
|
// Jetzt konvertiere zu linker oberer Ecke für die Rendering-Position
|
||||||
// Passe Koordinaten an: Die Spawn-Position ist die Straßenlinie, aber wir brauchen die linke obere Ecke des Autos
|
// Passe Koordinaten an: Die Spawn-Position ist die Straßenlinie, aber wir brauchen die linke obere Ecke des Autos
|
||||||
// Das Auto muss auf der Linie zentriert sein
|
// Das Auto muss auf der Linie zentriert sein
|
||||||
switch (randomDirection) {
|
switch (randomDirection) {
|
||||||
@@ -1587,21 +1804,18 @@ export default {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// laneCoord speichert die Zielspur (Mitte) auf der Querachse
|
|
||||||
// Verwende die bereits berechneten absoluten x/y, um exakt dieselbe Spur zu halten
|
|
||||||
const laneCoord = spawnPos.laneAxis === 'H'
|
|
||||||
? (y + carHeight / 2) // Y-Mitte
|
|
||||||
: (x + carWidth / 2); // X-Mitte
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
x: x,
|
x: x,
|
||||||
y: y,
|
y: y,
|
||||||
angle: spawnPos.angle,
|
angle: angle,
|
||||||
direction: spawnPos.direction,
|
direction: randomDirection,
|
||||||
laneAxis: spawnPos.laneAxis,
|
laneAxis: spawnPos.laneAxis,
|
||||||
laneCoord: laneCoord
|
laneCoord: laneCoord,
|
||||||
|
willTurn: turnInfo.willTurn,
|
||||||
|
turnDirection: turnInfo.turnDirection,
|
||||||
|
turnX: turnInfo.turnX,
|
||||||
|
turnY: turnInfo.turnY,
|
||||||
|
turnAngle: turnInfo.turnAngle
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1757,9 +1971,129 @@ export default {
|
|||||||
// Aktualisiere die Bewegung eines einzelnen Autos (vereinfachte Taxi-Logik)
|
// Aktualisiere die Bewegung eines einzelnen Autos (vereinfachte Taxi-Logik)
|
||||||
updateCarMovement(car) {
|
updateCarMovement(car) {
|
||||||
|
|
||||||
|
// 0) Prüfe ob das Auto abbiegen sollte (neue Turn-Logik)
|
||||||
|
if (car.willTurn && !car.hasTurnedAtIntersection) {
|
||||||
|
// Auto soll abbiegen - prüfe ob es die Turn-Position erreicht oder überschritten hat
|
||||||
|
const carCenterX = car.x + car.width / 2;
|
||||||
|
const carCenterY = car.y + car.height / 2;
|
||||||
|
|
||||||
// 1) An Abbiegepunkt? Dann (ggf.) vorgegebene Zielrichtung übernehmen
|
let shouldTurn = false;
|
||||||
const forcedDir = this.shouldCarTurnAtIntersection(car);
|
|
||||||
|
// Prüfe ob das Auto die Turn-Position erreicht hat (abhängig von der Fahrtrichtung)
|
||||||
|
if (car.direction === 'up') {
|
||||||
|
// Fährt nach oben - prüfe ob Y-Position erreicht ist
|
||||||
|
shouldTurn = carCenterY <= car.turnY;
|
||||||
|
} else if (car.direction === 'down') {
|
||||||
|
// Fährt nach unten - prüfe ob Y-Position erreicht ist
|
||||||
|
shouldTurn = carCenterY >= car.turnY;
|
||||||
|
} else if (car.direction === 'left') {
|
||||||
|
// Fährt nach links - prüfe ob X-Position erreicht ist
|
||||||
|
shouldTurn = carCenterX <= car.turnX;
|
||||||
|
} else if (car.direction === 'right') {
|
||||||
|
// Fährt nach rechts - prüfe ob X-Position erreicht ist
|
||||||
|
shouldTurn = carCenterX >= car.turnX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldTurn) {
|
||||||
|
// Merke alte Richtung und Position für Animation
|
||||||
|
const oldDirection = car.direction;
|
||||||
|
|
||||||
|
car.direction = car.turnDirection;
|
||||||
|
car.hasTurnedAtIntersection = true;
|
||||||
|
|
||||||
|
// Starte Animation für sanfte Drehung (0.5 Sekunden)
|
||||||
|
car.isTurning = true;
|
||||||
|
car.turnStartAngle = car.angle;
|
||||||
|
car.turnTargetAngle = car.turnAngle;
|
||||||
|
car.turnStartTime = Date.now();
|
||||||
|
car.turnDuration = 250; // 0.25 Sekunden
|
||||||
|
|
||||||
|
// Speichere Start- und Ziel-Position für smooth Interpolation
|
||||||
|
car.turnStartX = car.x;
|
||||||
|
car.turnStartY = car.y;
|
||||||
|
|
||||||
|
// Berechne Ziel-Position
|
||||||
|
if (oldDirection === 'up' || oldDirection === 'down') {
|
||||||
|
// War vertikal, wird horizontal - setze Y-Position auf turnY
|
||||||
|
car.turnTargetY = car.turnY - car.height / 2;
|
||||||
|
car.turnTargetX = car.x; // X bleibt gleich
|
||||||
|
} else {
|
||||||
|
// War horizontal, wird vertikal - setze X-Position auf turnX
|
||||||
|
car.turnTargetX = car.turnX - car.width / 2;
|
||||||
|
car.turnTargetY = car.y; // Y bleibt gleich
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aktualisiere laneAxis und laneCoord für die neue Richtung
|
||||||
|
// laneCoord ist die Position auf der Querachse (wo das Auto bleiben soll)
|
||||||
|
if (car.turnDirection === 'left' || car.turnDirection === 'right') {
|
||||||
|
// Fährt jetzt horizontal - X ändert sich, Y bleibt fix
|
||||||
|
car.laneAxis = 'H';
|
||||||
|
car.laneCoord = car.turnY; // Bleibe auf dieser Y-Position
|
||||||
|
} else {
|
||||||
|
// Fährt jetzt vertikal - Y ändert sich, X bleibt fix
|
||||||
|
car.laneAxis = 'V';
|
||||||
|
car.laneCoord = car.turnX; // Bleibe auf dieser X-Position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Animiere Drehung wenn Auto gerade abbiegt
|
||||||
|
if (car.isTurning) {
|
||||||
|
const now = Date.now();
|
||||||
|
const elapsed = now - car.turnStartTime;
|
||||||
|
const progress = Math.min(elapsed / car.turnDuration, 1.0); // 0.0 bis 1.0
|
||||||
|
|
||||||
|
// Easing-Funktion für smooth animation (ease-in-out)
|
||||||
|
const eased = progress < 0.5
|
||||||
|
? 2 * progress * progress
|
||||||
|
: 1 - Math.pow(-2 * progress + 2, 2) / 2;
|
||||||
|
|
||||||
|
// Normalisiere Winkel in [-π, π]
|
||||||
|
const normalizeAngle = (a) => {
|
||||||
|
while (a > Math.PI) a -= 2 * Math.PI;
|
||||||
|
while (a < -Math.PI) a += 2 * Math.PI;
|
||||||
|
return a;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Interpoliere Winkel
|
||||||
|
let startAngle = normalizeAngle(car.turnStartAngle);
|
||||||
|
let targetAngle = normalizeAngle(car.turnTargetAngle);
|
||||||
|
|
||||||
|
// Kürzesten Weg für Rotation finden mit atan2
|
||||||
|
// Berechne den Unterschied und verwende atan2 für korrekten Quadranten
|
||||||
|
let diff = Math.atan2(Math.sin(targetAngle - startAngle), Math.cos(targetAngle - startAngle));
|
||||||
|
|
||||||
|
// Debug: Log bei Start der Animation
|
||||||
|
if (elapsed < 50 && !car._loggedTurn) {
|
||||||
|
console.log(`Turn animation: start=${(startAngle * 180 / Math.PI).toFixed(1)}° target=${(targetAngle * 180 / Math.PI).toFixed(1)}° diff=${(diff * 180 / Math.PI).toFixed(1)}°`);
|
||||||
|
car._loggedTurn = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
car.angle = normalizeAngle(startAngle + diff * eased);
|
||||||
|
|
||||||
|
// Animation beenden wenn fertig
|
||||||
|
if (progress >= 1.0) {
|
||||||
|
car.isTurning = false;
|
||||||
|
car.angle = targetAngle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1) Alte Turn-Logik (nur für Autos ohne vorberechnete Turns - z.B. T-Kreuzungen ohne willTurn)
|
||||||
|
// Diese Logik wird nur noch für Tile-Typen ohne vorberechnete Turn-Info verwendet
|
||||||
|
let forcedDir = null;
|
||||||
|
if (!car.hasTurnedAtIntersection && !car.willTurn) {
|
||||||
|
forcedDir = this.shouldCarTurnAtIntersection(car);
|
||||||
|
// Strikter Zwang für T-Down: von unten kommend (direction 'up') niemals geradeaus weiter
|
||||||
|
const streetType = this.mapTileTypeToStreetCoordinates(this.getCurrentTileType());
|
||||||
|
if (!forcedDir && streetType === 'tDown' && car.direction === 'up') {
|
||||||
|
const cy = car.y + car.height / 2;
|
||||||
|
const tolAbs = 0.03 * this.tiles.size; // ~15px
|
||||||
|
const centerYAbs = 0.5 * this.tiles.size;
|
||||||
|
if (Math.abs(cy - centerYAbs) <= tolAbs || cy <= centerYAbs + tolAbs) {
|
||||||
|
forcedDir = Math.random() < 0.5 ? 'left' : 'right';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (forcedDir) {
|
if (forcedDir) {
|
||||||
const tileType = this.getCurrentTileType();
|
const tileType = this.getCurrentTileType();
|
||||||
// forcedDir hat Vorrang – NICHT durch allowedDirections einschränken
|
// forcedDir hat Vorrang – NICHT durch allowedDirections einschränken
|
||||||
@@ -1804,11 +2138,14 @@ export default {
|
|||||||
case 'right': newX = car.x + car.speed; break;
|
case 'right': newX = car.x + car.speed; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Querachse fixieren
|
// Querachse fixieren - Auto bleibt auf seiner Spur
|
||||||
|
// Während der Turn-Animation: Sanft zur neuen Spur gleiten
|
||||||
if (car.laneAxis === 'H') {
|
if (car.laneAxis === 'H') {
|
||||||
|
// Horizontale Bewegung - Y-Position fixieren
|
||||||
const centerY = car.laneCoord;
|
const centerY = car.laneCoord;
|
||||||
newY = centerY - car.height / 2;
|
newY = centerY - car.height / 2;
|
||||||
} else if (car.laneAxis === 'V') {
|
} else if (car.laneAxis === 'V') {
|
||||||
|
// Vertikale Bewegung - X-Position fixieren
|
||||||
const centerX = car.laneCoord;
|
const centerX = car.laneCoord;
|
||||||
newX = centerX - car.width / 2;
|
newX = centerX - car.width / 2;
|
||||||
}
|
}
|
||||||
@@ -3377,25 +3714,9 @@ export default {
|
|||||||
// Transformiere zum Zentrum des Autos für Rotation
|
// Transformiere zum Zentrum des Autos für Rotation
|
||||||
this.ctx.translate(centerX, centerY);
|
this.ctx.translate(centerX, centerY);
|
||||||
|
|
||||||
// Rotiere basierend auf der Fahrtrichtung (nicht angle)
|
// Verwende car.angle für smooth rotation während des Abbiegens
|
||||||
let rotationAngle = 0;
|
|
||||||
switch (car.direction) {
|
|
||||||
case 'up':
|
|
||||||
rotationAngle = -Math.PI / 2;
|
|
||||||
break;
|
|
||||||
case 'down':
|
|
||||||
rotationAngle = Math.PI / 2;
|
|
||||||
break;
|
|
||||||
case 'left':
|
|
||||||
rotationAngle = Math.PI;
|
|
||||||
break;
|
|
||||||
case 'right':
|
|
||||||
rotationAngle = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto-Bild korrigieren (90° + 180° für korrekte Ausrichtung)
|
// Auto-Bild korrigieren (90° + 180° für korrekte Ausrichtung)
|
||||||
const finalAngle = rotationAngle + Math.PI / 2 + Math.PI;
|
const finalAngle = car.angle + Math.PI / 2 + Math.PI;
|
||||||
this.ctx.rotate(finalAngle);
|
this.ctx.rotate(finalAngle);
|
||||||
|
|
||||||
if (this.carImage) {
|
if (this.carImage) {
|
||||||
|
|||||||
Reference in New Issue
Block a user