100 lines
3.2 KiB
JavaScript
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;
|
|
}
|
|
}
|