public static float?GetTileCost(PathfindingArgs pathfindingArgs, PathfindingNode start, PathfindingNode end) { if (!pathfindingArgs.NoClip && !Traversable(pathfindingArgs.CollisionMask, pathfindingArgs.Access, end)) { return(null); } if (!pathfindingArgs.AllowSpace && end.TileRef.Tile.IsEmpty) { return(null); } var cost = 1.0f; switch (pathfindingArgs.AllowDiagonals) { case true: cost *= OctileDistance(end, start); break; // Manhattan distance case false: cost *= ManhattanDistance(end, start); break; } return(cost); }
/// <summary> /// Ask for the pathfinder to gimme somethin /// </summary> /// <param name="pathfindingArgs"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public Job <Queue <TileRef> > RequestPath(PathfindingArgs pathfindingArgs, CancellationToken cancellationToken) { var startNode = GetNode(pathfindingArgs.Start); var endNode = GetNode(pathfindingArgs.End); var job = new AStarPathfindingJob(0.003, startNode, endNode, pathfindingArgs, cancellationToken); _pathfindingQueue.EnqueueJob(job); return(job); }
/// <summary> /// Gets all of the tiles in range that can we access /// </summary> /// If you want Dikstra then add distances. /// Doesn't use the JobQueue as it will generally be encapsulated by other jobs /// <param name="pathfindingArgs"></param> /// <param name="range"></param> /// <param name="fromStart">Whether we traverse from the starting tile or the end tile</param> /// <returns></returns> public static IEnumerable <PathfindingNode> GetNodesInRange(PathfindingArgs pathfindingArgs, bool fromStart = true) { var pathfindingSystem = EntitySystem.Get <PathfindingSystem>(); // Don't need a priority queue given not looking for shortest path var openTiles = new Queue <PathfindingNode>(); var closedTiles = new HashSet <TileRef>(); PathfindingNode startNode; if (fromStart) { startNode = pathfindingSystem.GetNode(pathfindingArgs.Start); } else { startNode = pathfindingSystem.GetNode(pathfindingArgs.End); } PathfindingNode currentNode; openTiles.Enqueue(startNode); while (openTiles.Count > 0) { currentNode = openTiles.Dequeue(); foreach (var neighbor in currentNode.GetNeighbors()) { // No distances stored so can just check closed tiles here if (closedTiles.Contains(neighbor.TileRef)) { continue; } closedTiles.Add(currentNode.TileRef); // So currently tileCost gets the octile distance between the 2 so we'll also use that for our range check var tileCost = PathfindingHelpers.GetTileCost(pathfindingArgs, startNode, neighbor); var direction = PathfindingHelpers.RelativeDirection(neighbor, currentNode); if (tileCost == null || tileCost > pathfindingArgs.Proximity || !PathfindingHelpers.DirectionTraversable(pathfindingArgs.CollisionMask, pathfindingArgs.Access, currentNode, direction)) { continue; } openTiles.Enqueue(neighbor); yield return(neighbor); } } }
public static bool TryEndNode(ref PathfindingNode endNode, PathfindingArgs pathfindingArgs) { if (!Traversable(pathfindingArgs.CollisionMask, pathfindingArgs.Access, endNode)) { if (pathfindingArgs.Proximity > 0.0f) { foreach (var node in BFSPathfinder.GetNodesInRange(pathfindingArgs, false)) { endNode = node; return(true); } } return(false); } return(true); }
public static bool TryEndNode(ref PathfindingNode endNode, PathfindingArgs pathfindingArgs) { if (!Traversable(pathfindingArgs.CollisionMask, endNode.CollisionMask)) { if (pathfindingArgs.Proximity > 0.0f) { // TODO: Should make this account for proximities, // probably some kind of breadth-first search to find a valid one foreach (var(direction, node) in endNode.Neighbors) { if (Traversable(pathfindingArgs.CollisionMask, node.CollisionMask)) { endNode = node; return(true); } } } return(false); } return(true); }