/// <summary> /// 목적지에서 가까운 갈수있는 타일을 찾는다. /// </summary> /// <param name="unit">목적지에 가는 주체</param> /// <param name="dest">목적지</param> /// <returns></returns> public static Tile GetClosestReachableDest(Unit unit, Vector2Int dest) { Tile curTile = FieldManager.GetTileClamp(dest); List <Tile> frontier = new List <Tile>() { curTile }; List <Tile> visited = new List <Tile>(); Vector2Int [] directions = { Vector2Int.up, Vector2Int.down, Vector2Int.right, Vector2Int.left }; int loop_count = 0; while (true) { InfiniteLoopDebug.Run("Pathfind", "GetClosestReachableDest", 140); // 무한루프 방지용 loop_count++; if (frontier.Count == 0 || loop_count > 1000) { Debug.Log("갈수 없거나 계산이 너무 오래걸립니다!"); return(null); } curTile = frontier[0]; visited.Add(curTile); frontier.RemoveAt(0); // if (curTile.IsPositionable(unit)) if (PathFindAlgorithm(/*unit,*/ unit.MoveSkill, unit.Position, curTile.position) != null) { return(curTile); } foreach (Vector2Int direction in directions) { Tile tile = FieldManager.GetTile(curTile.position + direction); if (tile != null && !visited.Contains(tile)) { frontier.Add(tile); } } } }
/// <summary> /// 유닛의 이동경로를 찾는 알고리즘. /// </summary> /// <param name="unit">이동 유닛</param> /// <param name="from">출발 위치</param> /// <param name="to">도착 위치</param> /// <returns></returns> public static List <Vector2Int> PathFindAlgorithm(Model.Unit agent, Vector2Int from, Vector2Int to) { if (FieldManager.GetTile(to) == null || FieldManager.GetTile(to).HasUnit()) { Debug.LogWarning("길찾기 알고리즘 오류"); return(null); } Node node = new Node(from, to); List <Node> frontier = new List <Node>(); // priority queue ordered by Path-Cost, with node as the only element List <Node> explored = new List <Node>(); // an empty set frontier.Add(node); while (true) { InfiniteLoopDebug.Run("Pathfind", "GetClosestReachableDest", 258); if (frontier.Count == 0) { Debug.Log("목적지에 갈수 있는 길이 존재하지 않습니다."); return(null); // 답이 없음. } node = Node.PopSmallestCostNode(frontier); frontier.Remove(node); if (node.unitPosition.Equals(to)) // goal test { return(Node.RebuildPath(node)); } explored.Add(node); // add node.State to explored foreach (var child in Node.GetAvilableNeighbor(agent, node)) { bool isExplored = false; foreach (var item in explored) { if (item.unitPosition == child.unitPosition) { isExplored = true; } } if (isExplored.Equals(true)) { continue; } bool isFrontiered = false; for (int i = frontier.Count - 1; i >= 0; i--) { if (frontier[i].unitPosition.Equals(child.unitPosition)) { isFrontiered = true; if (child.unitPosition == frontier[i].unitPosition && child.evaluationCost < frontier[i].evaluationCost) { frontier.Remove(frontier[i]); frontier.Add(child); } } } if (isFrontiered.Equals(false)) { frontier.Add(child); } } } }