using System.Collections.Generic; using UnityEngine; namespace GeometryTD.Pathfinding { public class GridMapPathfinder : IMapPathfinder { private static readonly Vector3Int[] NeighborOffsets = { new Vector3Int(1, 0, 0), new Vector3Int(-1, 0, 0), new Vector3Int(0, 1, 0), new Vector3Int(0, -1, 0) }; private readonly HashSet _walkableSet = new HashSet(); private readonly Queue _openQueue = new Queue(); private readonly Dictionary _cameFrom = new Dictionary(); public bool TryFindPath( IReadOnlyCollection walkableCells, Vector3Int startCell, Vector3Int destinationCell, IReadOnlyCollection blockedCells, List pathResult) { if (pathResult == null) { return false; } pathResult.Clear(); if (walkableCells == null || walkableCells.Count <= 0) { return false; } BuildWalkableSet(walkableCells); if (!_walkableSet.Contains(startCell) || !_walkableSet.Contains(destinationCell)) { return false; } _openQueue.Clear(); _cameFrom.Clear(); _openQueue.Enqueue(startCell); _cameFrom[startCell] = startCell; while (_openQueue.Count > 0) { Vector3Int currentCell = _openQueue.Dequeue(); if (currentCell == destinationCell) { BuildPath(destinationCell, pathResult); return true; } for (int i = 0; i < NeighborOffsets.Length; i++) { Vector3Int nextCell = currentCell + NeighborOffsets[i]; if (!_walkableSet.Contains(nextCell) || _cameFrom.ContainsKey(nextCell)) { continue; } if (IsBlocked(nextCell, blockedCells, startCell, destinationCell)) { continue; } _cameFrom[nextCell] = currentCell; _openQueue.Enqueue(nextCell); } } return false; } private void BuildWalkableSet(IReadOnlyCollection walkableCells) { _walkableSet.Clear(); foreach (Vector3Int cell in walkableCells) { _walkableSet.Add(cell); } } private void BuildPath(Vector3Int destinationCell, List pathResult) { pathResult.Clear(); Vector3Int current = destinationCell; while (true) { pathResult.Add(current); Vector3Int parent = _cameFrom[current]; if (parent == current) { break; } current = parent; } pathResult.Reverse(); } private static bool IsBlocked( Vector3Int cell, IReadOnlyCollection blockedCells, Vector3Int startCell, Vector3Int destinationCell) { if (blockedCells == null || blockedCells.Count <= 0) { return false; } if (cell == startCell || cell == destinationCell) { return false; } foreach (Vector3Int blockedCell in blockedCells) { if (blockedCell == cell) { return true; } } return false; } } }