Files
novafarma/src/utils/Pathfinding.js
2025-12-07 21:31:44 +01:00

100 lines
3.2 KiB
JavaScript

class Pathfinding {
constructor(scene) {
this.scene = scene;
// Offsets for 4 directions (Isometric grid)
this.dirs = [
{ x: 0, y: -1 }, // Up
{ x: 0, y: 1 }, // Down
{ x: -1, y: 0 }, // Left
{ x: 1, y: 0 } // Right
];
}
findPath(startX, startY, endX, endY, limit = 50) {
// Simple A* implementation
const startNode = { x: startX, y: startY, g: 0, h: 0, f: 0, parent: null };
const openList = [startNode];
const closedSet = new Set();
let count = 0;
while (openList.length > 0 && count < limit) {
count++;
// Sort by F cost (can be optimized with PriorityQueue)
openList.sort((a, b) => a.f - b.f);
const currentNode = openList.shift();
// Reached destination? (or close enough)
if (currentNode.x === endX && currentNode.y === endY) {
return this.reconstructPath(currentNode);
}
const key = `${currentNode.x},${currentNode.y}`;
closedSet.add(key);
// Explore neighbors
for (const dir of this.dirs) {
const neighborX = currentNode.x + dir.x;
const neighborY = currentNode.y + dir.y;
if (closedSet.has(`${neighborX},${neighborY}`)) continue;
// Check collision
if (!this.isValidMove(neighborX, neighborY)) continue;
const gScore = currentNode.g + 1;
const hScore = Math.abs(neighborX - endX) + Math.abs(neighborY - endY);
const fScore = gScore + hScore;
// Check if already in openList with lower G
const existing = openList.find(n => n.x === neighborX && n.y === neighborY);
if (existing) {
if (gScore < existing.g) {
existing.g = gScore;
existing.f = fScore;
existing.parent = currentNode;
}
} else {
openList.push({ x: neighborX, y: neighborY, g: gScore, h: hScore, f: fScore, parent: currentNode });
}
}
}
// Limit reached or no path - return simplified direction if possible
return null;
}
reconstructPath(node) {
const path = [];
let curr = node;
while (curr.parent) {
path.unshift({ x: curr.x, y: curr.y });
curr = curr.parent;
}
return path;
}
isValidMove(x, y) {
const terrain = this.scene.terrainSystem;
if (!terrain) return true;
// Bounds
if (x < 0 || y < 0 || x >= terrain.width || y >= terrain.height) return false;
// Tile Type
const tile = terrain.tiles[y][x];
if (tile.type.name === 'water') return false;
// Decorations collision
const key = `${x},${y}`;
if (terrain.decorationsMap.has(key)) {
const decor = terrain.decorationsMap.get(key);
const solidTypes = ['tree', 'stone', 'bush', 'wall', 'ruin', 'fence', 'house', 'gravestone'];
if (solidTypes.includes(decor.type)) return false;
}
return true;
}
}