import * as THREE from "three"; import { PATH_POINTS, GRID_CELL_SIZE } from "../config/gameConfig.js"; // Snap value to grid (to nearest grid line) export function snapToGrid(value, size = GRID_CELL_SIZE) { return Math.round(value / size) * size; } // Grid helpers to work with cell centers export function worldToCell(x, z, size = GRID_CELL_SIZE) { // Map world coords to integer col/row indices const col = Math.floor(x / size); const row = Math.floor(z / size); return { col, row }; } export function cellToWorldCenter(col, row, size = GRID_CELL_SIZE) { // Center of the tile: (col + 0.5, row + 0.5) * size return new THREE.Vector3((col + 0.5) * size, 0, (row + 0.5) * size); } // Check if point is on road export function isOnRoad(p, pathPoints = PATH_POINTS) { const halfWidth = 1.6; for (let i = 0; i < pathPoints.length - 1; i++) { const a = pathPoints[i]; const b = pathPoints[i + 1]; if (pointSegmentDistance2D(p, a, b) <= halfWidth) return true; } return false; } // Calculate distance from point to line segment in 2D export function pointSegmentDistance2D(p, a, b) { const apx = p.x - a.x, apz = p.z - a.z; const abx = b.x - a.x, abz = b.z - a.z; const abLenSq = abx * abx + abz * abz; let t = 0; if (abLenSq > 0) t = (apx * abx + apz * abz) / abLenSq; t = Math.max(0, Math.min(1, t)); const cx = a.x + t * abx, cz = a.z + t * abz; const dx = p.x - cx, dz = p.z - cz; return Math.hypot(dx, dz); } // Simple particle/hit effect system export class EffectSystem { constructor(scene) { this.scene = scene; this.effects = []; } spawnHitEffect(pos) { const geo = new THREE.SphereGeometry(0.2, 6, 6); const mat = new THREE.MeshBasicMaterial({ color: 0xfff176, transparent: true, opacity: 0.9, }); const m = new THREE.Mesh(geo, mat); m.position.copy(pos); this.scene.add(m); this.effects.push({ mesh: m, life: 0.25 }); } update(dt) { for (let i = this.effects.length - 1; i >= 0; i--) { const e = this.effects[i]; e.life -= dt; e.mesh.scale.addScalar(6 * dt); e.mesh.material.opacity = Math.max(0, e.life / 0.25); if (e.life <= 0) { this.scene.remove(e.mesh); this.effects.splice(i, 1); } } } }