import * as THREE from "three"; import { PATH_POINTS, ROAD_HALF_WIDTH, GRID_CELL_SIZE, } from "../config/gameConfig.js"; export class PathBuilder { constructor(scene) { this.scene = scene; // Clone and snap path points to the grid to ensure alignment this.pathPoints = PATH_POINTS.map((p) => { const snapped = p.clone ? p.clone() : new THREE.Vector3(p.x, p.y ?? 0, p.z); snapped.x = Math.round(snapped.x / GRID_CELL_SIZE) * GRID_CELL_SIZE; snapped.z = Math.round(snapped.z / GRID_CELL_SIZE) * GRID_CELL_SIZE; return snapped; }); this.roadMeshes = []; // Materials this.roadMat = new THREE.MeshStandardMaterial({ color: 0x393c41, metalness: 0.1, roughness: 0.9, }); } buildPath() { // Visualize path line this.createPathLine(); // Build straight road segments only (no bevels or rounded corners) for (let i = 0; i < this.pathPoints.length - 1; i++) { this.addSegment(this.pathPoints[i], this.pathPoints[i + 1]); } } createPathLine() { const pathLineMat = new THREE.LineBasicMaterial({ color: 0xffff00 }); const pathLineGeo = new THREE.BufferGeometry().setFromPoints( this.pathPoints ); const pathLine = new THREE.Line(pathLineGeo, pathLineMat); pathLine.position.y = 0.01; this.scene.add(pathLine); } addSegment(a, b) { const seg = new THREE.Vector3().subVectors(b, a); const len = seg.length(); if (len <= 0.0001) return; const mid = new THREE.Vector3().addVectors(a, b).multiplyScalar(0.5); const roadGeo = new THREE.BoxGeometry(len, 0.1, ROAD_HALF_WIDTH * 2); const road = new THREE.Mesh(roadGeo, this.roadMat); road.castShadow = false; road.receiveShadow = true; road.position.set(mid.x, 0.05, mid.z); const angle = Math.atan2(seg.z, seg.x); road.rotation.y = -angle; this.scene.add(road); this.roadMeshes.push(road); } }