/// <summary> /// Initializes a discrete grid using the information provided. /// </summary> /// <param name="startPoint">The point to start the route at</param> /// <param name="endPoint">The point to end the route at</param> /// <param name="field">The field that needs to be discretised</param> /// <param name="gridSize">The size of the grid to be palced placed over <paramref name="field"/></param> /// <param name="movingObject">The object that will be moving.</param> /// <returns>A GridSquare array, initialized to represent <paramref name="field"/>.</returns> /// /// Produces a GridSquare array that is set up for use by <see cref="FindPath"/>. /// /// Uses the ObjectClearance and <paramref name="movingObject" />'s <see cref="IPositionedObject.Size"/> property to determine the /// apparent size of opponents, and marks the squares that contain them as <see cref="SquareType.Obstacle"/>. /// /// Marks the square that contains <paramref name="endPoint" /> as <see cref="SquareType.Destination"/>. /// /// Marks the square that contains <paramref name="startPoint" /> as <see cref="SquareType.Origin"/>. /// /// Works in parallel as far as possible, using the Microsoft Task Parallel Library (http://msdn.microsoft.com/en-us/library/dd460717.aspx). protected GridSquare[] InitGrid(PointF startPoint, PointF endPoint, Field field, Size gridSize, IPositionedObject movingObject) { var playersize = (movingObject.Size + new Size(ObjectClearance, ObjectClearance)).Scale(Resolution).Scale(2.0f).Ceiling(); var clearance = Math.Max(playersize.Width, playersize.Height); // The amount to increase an obstacle's size by to allow for the player's size var grid = new GridSquare[gridSize.Height * gridSize.Width]; // Initialize the grid Parallel.For(0, grid.Length, i => { grid[i] = new GridSquare { Location = PointExtensions.FromIndex(i, gridSize.Width) }; }); Parallel.ForEach(from p in field.Players where p.Team == Team.Opposition select p, player => { var centerGridPoint = player.Position.Scale(Resolution).Floor(); var minX = Math.Max(0, centerGridPoint.X - playersize.Width - clearance); var maxX = Math.Min(centerGridPoint.X + playersize.Width + clearance, gridSize.Width); var minY = Math.Max(0, centerGridPoint.Y - playersize.Height - clearance); var maxY = Math.Min(centerGridPoint.Y + playersize.Height + clearance, gridSize.Height); for (var i = minX; i < maxX; i++) { for (var j = minY; j < maxY; j++) { if (i < 0 || j < 0) { continue; } var gridPoint = new Point(i, j); grid[gridPoint.ToIndex(gridSize.Width)].Type = SquareType.Obstacle; } } }); var gridEndPoint = endPoint.Scale(Resolution).Floor(); grid[gridEndPoint.ToIndex(gridSize.Width)].Type = SquareType.Destination; var gridStartPoint = startPoint.Scale(Resolution).Floor(); grid[gridStartPoint.ToIndex(gridSize.Width)].Type = SquareType.Origin; return(grid); }
/// <summary> /// Calculates the heuristic score for the given square. /// </summary> /// <param name="square">The square to calculate the heuristic for </param> /// <param name="endPoint">The current point to aim for </param> /// <returns> /// \f$+\infty\f$ if the square is an obstacle /// /// CalculateLength(square.Location, endPoint) otherwise /// </returns> protected float CalculateHeuristic(GridSquare square, PointF endPoint) { return(square.Type == SquareType.Obstacle ? float.PositiveInfinity : CalculateLength(square.Location, endPoint)); }
/// <summary> /// Reconstructs a path from the given cameFrom information. /// </summary> /// <param name="cameFrom">The list of 'came from' details produced by the A* algorithm</param> /// <param name="currentSquare">The current square to examine</param> /// <returns>The shortest Route to the destination</returns> /// /// A recursive algorithm that reconstructs the path that has been produced by the A* algorithm protected Route ReconstructPath(Dictionary <GridSquare, GridSquare> cameFrom, GridSquare currentSquare) { if (cameFrom.ContainsKey(currentSquare)) { var path = ReconstructPath(cameFrom, cameFrom[currentSquare]); path.Path.Add(new LineSegment(cameFrom[currentSquare].Location, currentSquare.Location)); return(path); } return(new Route()); }