public static List <VoronoiCell> GeneratePath(List <VoronoiCell> targetCells, List <VoronoiCell> cells, Rectangle limits) { Stopwatch sw2 = new Stopwatch(); sw2.Start(); List <VoronoiCell> pathCells = new List <VoronoiCell>(); VoronoiCell currentCell = targetCells[0]; currentCell.CellType = CellType.Path; pathCells.Add(currentCell); int currentTargetIndex = 0; int iterationsLeft = cells.Count; do { int edgeIndex = 0; double smallestDist = double.PositiveInfinity; for (int i = 0; i < currentCell.Edges.Count; i++) { var adjacentCell = currentCell.Edges[i].AdjacentCell(currentCell); if (adjacentCell == null) { continue; } double dist = MathUtils.Distance(adjacentCell.Site.Coord.X, adjacentCell.Site.Coord.Y, targetCells[currentTargetIndex].Site.Coord.X, targetCells[currentTargetIndex].Site.Coord.Y); dist += MathUtils.Distance(adjacentCell.Site.Coord.X, adjacentCell.Site.Coord.Y, currentCell.Site.Coord.X, currentCell.Site.Coord.Y) * 0.5f; //disfavor small edges to prevent generating a very small passage if (Vector2.Distance(currentCell.Edges[i].Point1, currentCell.Edges[i].Point2) < 200.0f) { dist += 1000000; } if (dist < smallestDist) { edgeIndex = i; smallestDist = dist; } } currentCell = currentCell.Edges[edgeIndex].AdjacentCell(currentCell); currentCell.CellType = CellType.Path; pathCells.Add(currentCell); iterationsLeft--; if (currentCell == targetCells[currentTargetIndex]) { currentTargetIndex++; if (currentTargetIndex >= targetCells.Count) { break; } } } while (currentCell != targetCells[targetCells.Count - 1] && iterationsLeft > 0); Debug.WriteLine("gettooclose: " + sw2.ElapsedMilliseconds + " ms"); sw2.Restart(); return(pathCells); }
public static List<VoronoiCell> GeneratePath( List<VoronoiCell> targetCells, List<VoronoiCell> cells, List<VoronoiCell>[,] cellGrid, int gridCellSize, Rectangle limits, float wanderAmount = 0.3f, bool mirror = false) { Stopwatch sw2 = new Stopwatch(); sw2.Start(); //how heavily the path "steers" towards the endpoint //lower values will cause the path to "wander" more, higher will make it head straight to the end wanderAmount = MathHelper.Clamp(wanderAmount, 0.0f, 1.0f); List<GraphEdge> allowedEdges = new List<GraphEdge>(); List<VoronoiCell> pathCells = new List<VoronoiCell>(); VoronoiCell currentCell = targetCells[0]; currentCell.CellType = CellType.Path; pathCells.Add(currentCell); int currentTargetIndex = 1; int iterationsLeft = cells.Count; do { int edgeIndex = 0; allowedEdges.Clear(); foreach (GraphEdge edge in currentCell.Edges) { var adjacentCell = edge.AdjacentCell(currentCell); if (limits.Contains(adjacentCell.Site.Coord.X, adjacentCell.Site.Coord.Y)) { allowedEdges.Add(edge); } } //steer towards target if (Rand.Range(0.0f, 1.0f, Rand.RandSync.Server) > wanderAmount || allowedEdges.Count == 0) { double smallestDist = double.PositiveInfinity; for (int i = 0; i < currentCell.Edges.Count; i++) { var adjacentCell = currentCell.Edges[i].AdjacentCell(currentCell); double dist = MathUtils.Distance( adjacentCell.Site.Coord.X, adjacentCell.Site.Coord.Y, targetCells[currentTargetIndex].Site.Coord.X, targetCells[currentTargetIndex].Site.Coord.Y); if (dist < smallestDist) { edgeIndex = i; smallestDist = dist; } } } //choose random edge (ignoring ones where the adjacent cell is outside limits) else { edgeIndex = Rand.Int(allowedEdges.Count, Rand.RandSync.Server); if (mirror && edgeIndex > 0) edgeIndex = allowedEdges.Count - edgeIndex; edgeIndex = currentCell.Edges.IndexOf(allowedEdges[edgeIndex]); } currentCell = currentCell.Edges[edgeIndex].AdjacentCell(currentCell); currentCell.CellType = CellType.Path; pathCells.Add(currentCell); iterationsLeft--; if (currentCell == targetCells[currentTargetIndex]) { currentTargetIndex += 1; if (currentTargetIndex >= targetCells.Count) break; } } while (currentCell != targetCells[targetCells.Count - 1] && iterationsLeft > 0); Debug.WriteLine("gettooclose: " + sw2.ElapsedMilliseconds + " ms"); sw2.Restart(); return pathCells; }
public static List <VoronoiCell> GeneratePath(List <VoronoiCell> targetCells, List <VoronoiCell> cells) { Stopwatch sw2 = new Stopwatch(); sw2.Start(); List <VoronoiCell> pathCells = new List <VoronoiCell>(); if (targetCells.Count == 0) { return(pathCells); } VoronoiCell currentCell = targetCells[0]; currentCell.CellType = CellType.Path; pathCells.Add(currentCell); int currentTargetIndex = 0; int iterationsLeft = cells.Count / 2; do { int edgeIndex = 0; double smallestDist = double.PositiveInfinity; for (int i = 0; i < currentCell.Edges.Count; i++) { var adjacentCell = currentCell.Edges[i].AdjacentCell(currentCell); if (adjacentCell == null) { continue; } double dist = MathUtils.Distance(adjacentCell.Site.Coord.X, adjacentCell.Site.Coord.Y, targetCells[currentTargetIndex].Site.Coord.X, targetCells[currentTargetIndex].Site.Coord.Y); dist += MathUtils.Distance(adjacentCell.Site.Coord.X, adjacentCell.Site.Coord.Y, currentCell.Site.Coord.X, currentCell.Site.Coord.Y) * 0.5f; //disfavor short edges to prevent generating a very small passage if (Vector2.DistanceSquared(currentCell.Edges[i].Point1, currentCell.Edges[i].Point2) < 150.0f * 150.0f) { //divide by the number of times the current cell has been used // prevents the path from getting "stuck" (jumping back and forth between adjacent cells) // if there's no other way to the destination than going through a short edge dist *= 10.0f / Math.Max(pathCells.Count(c => c == currentCell), 1.0f); } if (dist < smallestDist) { edgeIndex = i; smallestDist = dist; } } currentCell = currentCell.Edges[edgeIndex].AdjacentCell(currentCell); currentCell.CellType = CellType.Path; pathCells.Add(currentCell); iterationsLeft--; if (currentCell == targetCells[currentTargetIndex]) { currentTargetIndex++; if (currentTargetIndex >= targetCells.Count) { break; } } } while (currentCell != targetCells[targetCells.Count - 1] && iterationsLeft > 0); Debug.WriteLine("gettooclose: " + sw2.ElapsedMilliseconds + " ms"); sw2.Restart(); return(pathCells); }