// если путь не найден, запускается таймер на повторный поиск пути public void OnPathNotFound(FinishNotFoundReasons reason) { if (attemptCount == 0 || Vector2Int.Distance(this.gridPosition, gridFinishPosition) <= GameConstants.StopMoveMinDistance) { return; } attemptCount--; timer.SetTimer(reason == FinishNotFoundReasons.Blocked ? GameConstants.PathFindBlockedTime : GameConstants.PathFindAttemptTime); }
/// <summary> /// Функция поиска пути /// </summary> public void FindPath() { startTime = DateTime.UtcNow; // получение времени начала работы FinishNotFoundReasons notFoundReason = FinishNotFoundReasons.None; bool[,] scannedCells = new bool[GameParams.Width, GameParams.Length]; // просмотренные ячейки PriorityQueue <NavGridPoint> queue = new PriorityQueue <NavGridPoint>(); // очередь с приоритетом из навигационных точек NavGridPoint point = new NavGridPoint(start, 0), movePoint; point.distance = GetDistance(start, finish); // получение дистанции между стартом и финишом queue.Add(point); scannedCells[start.x, start.y] = true; // пока очередь не пустая, поиск пути актуален и поток не должен быть завершён while (queue.Count != 0 && IsActual && (FindThread == null || (FindThread.ThreadState & ThreadState.AbortRequested) == 0)) { // если финиш занят, выходим из цикла if (TerrainNavGrid.Instance.IsCellUsed(finish)) { notFoundReason = FinishNotFoundReasons.FinishUsed; break; } point = queue.GetMin(); // если текущая позиция равна финишу, то выходим из цикла if (point.Position == finish) { IsPathFound = true; break; } if (IsPositionBlocked(point.Position)) { notFoundReason = FinishNotFoundReasons.Blocked; break; } // находим соседние клетки, ближайшие к финишу foreach (Vector2Int move in MoveArray) { movePoint = new NavGridPoint(point.Position + move, point.order + 1); if (!IsPointInField(movePoint.Position) || TerrainNavGrid.Instance.IsCellUsed(movePoint.Position) || TerrainHeightMap.Instance.GetHeight(movePoint.Position) > TerrainHeightMap.Instance.GetHeight(point.Position) + maxHeight) { continue; } // пропускает поинт, если он вне карты, занят или выше текущей позиции //float heightDist = TerrainHeightMap.Instance.GetHeight(movePoint.Position) - TerrainHeightMap.Instance.GetHeight(point.Position); //if (heightDist < 0) heightDist = 0; movePoint.oldPoint = point; movePoint.distance = GetDistance(movePoint.Position, finish) /* + heightDist*/; if (scannedCells[movePoint.Position.x, movePoint.Position.y]) // если позиция просмотрена { if (queue.Contains(movePoint)) // если в очереди уже есть такая позиция, то берётся ближайшая к финишу { NavGridPoint remove = queue.Find(movePoint); if (remove.Weight < movePoint.Weight) { continue; } queue.Remove(remove); queue.Add(movePoint); } continue; } scannedCells[movePoint.Position.x, movePoint.Position.y] = true; queue.Add(movePoint); // добавление поинта в очередь с приоритетом } } IsComplete = true; if (IsPathFound) // если путь найден, получаем список координат { while (point.oldPoint != null) { path.Add(point.Position); point = point.oldPoint; } if (onPathfound == null) { return; } onPathfound.BeginInvoke(path, null, null); } else { // иначе сообщаем причину if (notFoundReason == FinishNotFoundReasons.None) { notFoundReason = FinishNotFoundReasons.PathNotFound; } if (onPathNotFound == null) { return; } onPathNotFound.BeginInvoke(notFoundReason, null, null); } }