110 lines
2.9 KiB
JavaScript
110 lines
2.9 KiB
JavaScript
import * as THREE from 'three';
|
|
|
|
export class VehicleSystem {
|
|
constructor(scene) {
|
|
this.scene = scene;
|
|
this.buses = []; // { mesh, points, dists, totalLen, currentDist, speed, direction, routeIndex }
|
|
|
|
this.busGeom = new THREE.BoxGeometry(3.5, 4.0, 10.0);
|
|
this.busGeom.translate(0, 3.5, 0);
|
|
|
|
this.baseBusMat = new THREE.MeshStandardMaterial({
|
|
color: 0xF59E0B,
|
|
emissive: 0xB45309,
|
|
emissiveIntensity: 0.2,
|
|
roughness: 0.2
|
|
});
|
|
}
|
|
|
|
addBusToRoute(routePathPoints, colorStr, routeIndex) {
|
|
if (!routePathPoints || routePathPoints.length < 2) return;
|
|
|
|
const points = routePathPoints.map(p => p.clone());
|
|
|
|
// Create material specific to this bus/route
|
|
const mat = this.baseBusMat.clone();
|
|
if (colorStr) {
|
|
mat.color.set(colorStr);
|
|
// Slight emissive tint of same color
|
|
const c = new THREE.Color(colorStr);
|
|
mat.emissive.set(c.multiplyScalar(0.5));
|
|
}
|
|
|
|
const mesh = new THREE.Mesh(this.busGeom, mat);
|
|
mesh.position.copy(points[0]);
|
|
mesh.castShadow = true;
|
|
this.scene.add(mesh);
|
|
|
|
// Pre-calculate
|
|
let totalLen = 0;
|
|
const dists = [0];
|
|
for (let i = 0; i < points.length - 1; i++) {
|
|
const d = points[i].distanceTo(points[i + 1]);
|
|
totalLen += d;
|
|
dists.push(totalLen);
|
|
}
|
|
|
|
this.buses.push({
|
|
mesh: mesh,
|
|
points: points,
|
|
dists: dists,
|
|
totalLen: totalLen,
|
|
currentDist: 0,
|
|
speed: 40,
|
|
direction: 1,
|
|
routeIndex: routeIndex
|
|
});
|
|
}
|
|
|
|
updateRouteColor(routeIndex, hexColor) {
|
|
// Update all buses belonging to this route
|
|
this.buses.forEach(bus => {
|
|
if (bus.routeIndex === routeIndex) {
|
|
bus.mesh.material.color.set(hexColor);
|
|
const c = new THREE.Color(hexColor);
|
|
bus.mesh.material.emissive.set(c.multiplyScalar(0.5));
|
|
}
|
|
});
|
|
}
|
|
|
|
clearVehicles() {
|
|
this.buses.forEach(bus => {
|
|
this.scene.remove(bus.mesh);
|
|
bus.mesh.geometry.dispose();
|
|
bus.mesh.material.dispose();
|
|
});
|
|
this.buses = [];
|
|
}
|
|
|
|
update(deltaTime) {
|
|
this.buses.forEach(bus => {
|
|
bus.currentDist += bus.speed * deltaTime * bus.direction;
|
|
|
|
if (bus.currentDist >= bus.totalLen) {
|
|
bus.currentDist = bus.totalLen;
|
|
bus.direction = -1;
|
|
} else if (bus.currentDist <= 0) {
|
|
bus.currentDist = 0;
|
|
bus.direction = 1;
|
|
}
|
|
|
|
let i = 0;
|
|
while (i < bus.dists.length - 2 && bus.currentDist > bus.dists[i + 1]) {
|
|
i++;
|
|
}
|
|
|
|
const startDist = bus.dists[i];
|
|
const endDist = bus.dists[i + 1];
|
|
const segmentLen = endDist - startDist;
|
|
|
|
const alpha = segmentLen > 0.0001 ? (bus.currentDist - startDist) / segmentLen : 0;
|
|
const pStart = bus.points[i];
|
|
const pEnd = bus.points[i + 1];
|
|
|
|
bus.mesh.position.lerpVectors(pStart, pEnd, alpha);
|
|
const lookTarget = bus.direction === 1 ? pEnd : pStart;
|
|
bus.mesh.lookAt(lookTarget);
|
|
});
|
|
}
|
|
}
|