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); }
public static bool DirectionTraversable(int collisionMask, ICollection <string> access, PathfindingNode currentNode, Direction direction) { // If it's a diagonal we need to check NSEW to see if we can get to it and stop corner cutting, NE needs N and E etc. // Given there's different collision layers stored for each node in the graph it's probably not worth it to cache this // Also this will help with corner-cutting PathfindingNode northNeighbor = null; PathfindingNode southNeighbor = null; PathfindingNode eastNeighbor = null; PathfindingNode westNeighbor = null; foreach (var neighbor in currentNode.GetNeighbors()) { if (neighbor.TileRef.X == currentNode.TileRef.X && neighbor.TileRef.Y == currentNode.TileRef.Y + 1) { northNeighbor = neighbor; continue; } if (neighbor.TileRef.X == currentNode.TileRef.X + 1 && neighbor.TileRef.Y == currentNode.TileRef.Y) { eastNeighbor = neighbor; continue; } if (neighbor.TileRef.X == currentNode.TileRef.X && neighbor.TileRef.Y == currentNode.TileRef.Y - 1) { southNeighbor = neighbor; continue; } if (neighbor.TileRef.X == currentNode.TileRef.X - 1 && neighbor.TileRef.Y == currentNode.TileRef.Y) { westNeighbor = neighbor; continue; } } switch (direction) { case Direction.NorthEast: if (northNeighbor == null || eastNeighbor == null) { return(false); } if (!Traversable(collisionMask, access, northNeighbor) || !Traversable(collisionMask, access, eastNeighbor)) { return(false); } break; case Direction.NorthWest: if (northNeighbor == null || westNeighbor == null) { return(false); } if (!Traversable(collisionMask, access, northNeighbor) || !Traversable(collisionMask, access, westNeighbor)) { return(false); } break; case Direction.SouthWest: if (southNeighbor == null || westNeighbor == null) { return(false); } if (!Traversable(collisionMask, access, southNeighbor) || !Traversable(collisionMask, access, westNeighbor)) { return(false); } break; case Direction.SouthEast: if (southNeighbor == null || eastNeighbor == null) { return(false); } if (!Traversable(collisionMask, access, southNeighbor) || !Traversable(collisionMask, access, eastNeighbor)) { return(false); } break; } return(true); }
public static float ManhattanDistance(PathfindingNode endNode, PathfindingNode currentNode) { return(Math.Abs(currentNode.TileRef.X - endNode.TileRef.X) + Math.Abs(currentNode.TileRef.Y - endNode.TileRef.Y)); }
/// <summary> /// This will reconstruct the path and fill in the tile holes as well /// </summary> /// <param name="cameFrom"></param> /// <param name="current"></param> /// <returns></returns> public static Queue <TileRef> ReconstructJumpPath(Dictionary <PathfindingNode, PathfindingNode> cameFrom, PathfindingNode current) { var running = new Stack <TileRef>(); running.Push(current.TileRef); while (cameFrom.ContainsKey(current)) { var previousCurrent = current; current = cameFrom[current]; var intermediate = previousCurrent; cameFrom.Remove(previousCurrent); var pathfindingSystem = IoCManager.Resolve <IEntitySystemManager>().GetEntitySystem <PathfindingSystem>(); var mapManager = IoCManager.Resolve <IMapManager>(); var grid = mapManager.GetGrid(current.TileRef.GridIndex); // Get all the intermediate nodes while (true) { var xOffset = 0; var yOffset = 0; if (intermediate.TileRef.X < current.TileRef.X) { xOffset += 1; } else if (intermediate.TileRef.X > current.TileRef.X) { xOffset -= 1; } else { xOffset = 0; } if (intermediate.TileRef.Y < current.TileRef.Y) { yOffset += 1; } else if (intermediate.TileRef.Y > current.TileRef.Y) { yOffset -= 1; } else { yOffset = 0; } intermediate = pathfindingSystem.GetNode(grid.GetTileRef( new Vector2i(intermediate.TileRef.X + xOffset, intermediate.TileRef.Y + yOffset))); if (intermediate.TileRef != current.TileRef) { // Hacky corner cut fix running.Push(intermediate.TileRef); continue; } break; } running.Push(current.TileRef); } var result = new Queue <TileRef>(running); return(result); }
public static Queue <TileRef> ReconstructPath(Dictionary <PathfindingNode, PathfindingNode> cameFrom, PathfindingNode current) { var running = new Stack <TileRef>(); running.Push(current.TileRef); while (cameFrom.ContainsKey(current)) { var previousCurrent = current; current = cameFrom[current]; cameFrom.Remove(previousCurrent); running.Push(current.TileRef); } var result = new Queue <TileRef>(running); return(result); }
public static bool Traversable(int collisionMask, ICollection <string> access, PathfindingNode node) { if ((collisionMask & node.BlockedCollisionMask) != 0) { return(false); } foreach (var reader in node.AccessReaders) { if (!reader.IsAllowed(access)) { return(false); } } return(true); }
public static bool DirectionTraversable(int collisionMask, ICollection <string> access, PathfindingNode currentNode, Direction direction) { // If it's a diagonal we need to check NSEW to see if we can get to it and stop corner cutting, NE needs N and E etc. // Given there's different collision layers stored for each node in the graph it's probably not worth it to cache this // Also this will help with corner-cutting currentNode.Neighbors.TryGetValue(Direction.North, out var northNeighbor); currentNode.Neighbors.TryGetValue(Direction.South, out var southNeighbor); currentNode.Neighbors.TryGetValue(Direction.East, out var eastNeighbor); currentNode.Neighbors.TryGetValue(Direction.West, out var westNeighbor); switch (direction) { case Direction.NorthEast: if (northNeighbor == null || eastNeighbor == null) { return(false); } if (!Traversable(collisionMask, access, northNeighbor) || !Traversable(collisionMask, access, eastNeighbor)) { return(false); } break; case Direction.NorthWest: if (northNeighbor == null || westNeighbor == null) { return(false); } if (!Traversable(collisionMask, access, northNeighbor) || !Traversable(collisionMask, access, westNeighbor)) { return(false); } break; case Direction.SouthWest: if (southNeighbor == null || westNeighbor == null) { return(false); } if (!Traversable(collisionMask, access, southNeighbor) || !Traversable(collisionMask, access, westNeighbor)) { return(false); } break; case Direction.SouthEast: if (southNeighbor == null || eastNeighbor == null) { return(false); } if (!Traversable(collisionMask, access, southNeighbor) || !Traversable(collisionMask, access, eastNeighbor)) { return(false); } break; } return(true); }