void UpdateNode(InternalPathNode from, InternalPathNode neighbor) { switch (neighbor.action) { case ActionType.WALK: var parent = parents.Get(from); InternalPathNode visibleParent = HasLineOfSight(parent.coord, neighbor.coord) ? parent : from; float cost = movementCosts.Get(visibleParent.coord) + Distance(visibleParent.coord, neighbor.coord) + level.GetCost(neighbor.coord); TrySetNodeValues(neighbor, visibleParent, cost); break; case ActionType.JUMP: TrySetNodeValues(neighbor, from, movementCosts.Get(from.coord) + jumpCost); break; case ActionType.FALL: TrySetNodeValues(neighbor, from, movementCosts.Get(from.coord) + fallCost); break; case ActionType.GAP_JUMP: TrySetNodeValues(neighbor, from, movementCosts.Get(from.coord) + gapJumpCost); break; default: Debug.LogWarning("Could not finding movement type for " + neighbor); break; } }
IEnumerator Pathfind() { frontier.Enqueue(new InternalPathNode(startPos, ActionType.WALK), 0); movementCosts.Set(startPos, 0); parents.Set(startPos, new InternalPathNode(startPos, ActionType.WALK)); closestDistance = int.MaxValue; InternalPathNode current; var cycles = 0; while (frontier.Count > 0) { ++cycles; current = frontier.Dequeue(); var adj = GetAdjacent(current.coord); foreach (var pos in adj) { if (!IsClosed(pos.coord)) { if (!frontier.Contains(pos)) { movementCosts.Set(pos.coord, Mathf.Infinity); // so (new < orig) comparison works } UpdateNode(current, pos); if (pos.coord == endPos) { ReconstructPath(pos); yield break; } if (HexUtil.DistanceFlat(pos.coord, endPos) < closestDistance) { closestDistance = HexUtil.DistanceFlat(pos.coord, endPos); closestPoint = pos; } } } if (cycles >= cyclesPerFrame) { cycles = 0; yield return(null); } } // endpos was not on connected graph; return closest node ReconstructPath(closestPoint); }
void TrySetNodeValues(InternalPathNode neighbor, InternalPathNode from, float cost) { if (cost < movementCosts.Get(neighbor.coord)) // only update if it's more efficient { movementCosts.Set(neighbor.coord, cost); parents.Set(neighbor.coord, from); AddToFrontier(neighbor); } }
void AddToFrontier(InternalPathNode pos) { var f = movementCosts.Get(pos.coord) + Heuristic(pos.coord); if (frontier.Contains(pos)) { frontier.UpdatePriority(pos, f); } else { frontier.Enqueue(pos, f); } }
void ReconstructPath(InternalPathNode lastPos) { path.Clear(); InternalPathNode cur = lastPos; while (true) { path.Add(new PathNode(HexUtil.ToWorld(cur.coord), cur.action)); if (cur.coord == startPos) { break; } cur = parents.Get(cur.coord); } path.Reverse(); if (OnPathCompleted != null) { OnPathCompleted(path); } }