public static Room FindNearestRoom(Tile start) { Path_AStar tileResolver = new Path_AStar(World.Current, start, GoalHasRoomEvaluator(), DijkstraDistance()); List <Tile> pathToRoom = tileResolver.GetList(); if (tileResolver.Length() >= 1) { return(tileResolver.EndTile().Room); } return(null); }
/// <summary> /// Finds the path to any inventory with type in <paramref name="types"/> /// </summary> public static List <Tile> FindPathToInventory(Tile start, string[] types, bool canTakeFromStockpile = true) { if (start == null || types == null || types.Length == 0) { return(null); } RoomPath_AStar roomResolver = new RoomPath_AStar(World.Current, start.GetNearestRoom(), RoomGoalInventoryEvaluator(types, canTakeFromStockpile), RoomHeuristic()); List <Room> roomPath = roomResolver.GetList(); if (roomPath.Count >= 1) { Tile nearestExit; if (roomPath.Count == 1) { nearestExit = start; } else { nearestExit = GetNearestExit(roomPath); } Tile targetTile = null; float distance = 0f; foreach (Inventory inventory in World.Current.InventoryManager.Inventories.Where(dictEntry => types.Contains(dictEntry.Key)).SelectMany(dictEntry => dictEntry.Value)) { if (inventory.Tile == null || !inventory.CanBePickedUp(canTakeFromStockpile)) { continue; } if (targetTile == null || Vector3.Distance(nearestExit.Vector3, inventory.Tile.Vector3) < distance) { distance = Vector3.Distance(nearestExit.Vector3, inventory.Tile.Vector3); targetTile = inventory.Tile; } } return(FindPathToTile(start, targetTile)); } else { // Since we don't have a roomPath, someone's done something weird, like a room of doors, so just use Dijkstra to find our way Path_AStar resolver = new Path_AStar(World.Current, start, GoalInventoryEvaluator(types, canTakeFromStockpile), DijkstraDistance()); List <Tile> path = resolver.GetList(); return(path); } }
/// <summary> /// Finds the path to a nearby tile where inventory of type <paramref name="type"/> can be dumped. /// </summary> public static List <Tile> FindPathToDumpInventory(Tile start, string type, int amount) { if (start == null || type == null || amount <= 0) { return(null); } Path_AStar resolver = new Path_AStar(World.Current, start, GoalCanFitInventoryEvaluator(type, amount), DijkstraDistance()); List <Tile> path = resolver.GetList(); DebugLogIf(path.Count > 0, "FindPathToDumpInventory from: {0}, to: {1}, found {2} [Length: {3}, took: {4}ms]", start, type, path.LastOrDefault(), path.Count, (int)(resolver.Duration * 1000)); DebugLogIf(path == null, "Failed to find path to furniture of type {0}", type); return(path); }
/// <summary> /// Finds the path to an inventory of type <paramref name="type"/>. /// </summary> public static List <Tile> FindPathToInventory(Tile start, string type, bool canTakeFromStockpile = true) { if (start == null || type == null) { return(null); } Path_AStar resolver = new Path_AStar(World.Current, start, GoalInventoryEvaluator(type, canTakeFromStockpile), DijkstraDistance()); List <Tile> path = resolver.GetList(); DebugLogIf(path.Count > 0, "FindPathToInventory from: {0}, to: {1}, found {2} [Length: {3}, took: {4}ms]", start, type, path.LastOrDefault(), path.Count, (int)(resolver.Duration * 1000)); DebugLogIf(path == null, "Failed to find path to inventory of type {0}", type); return(path); }
/// <summary> /// Finds the path to furniture. /// </summary> /// <returns>The path to furniture.</returns> /// <param name="start">Start tile.</param> /// <param name="objectType">Object type of the furniture.</param> public static List <Tile> FindPathToFurniture(Tile start, string type) { if (start == null || type == null) { return(null); } RoomPath_AStar roomResolver = new RoomPath_AStar(World.Current, start.GetNearestRoom(), RoomGoalFurnitureEvaluator(type), RoomHeuristic()); List <Room> roomPath = roomResolver.GetList(); if (roomPath.Count >= 1) { Tile nearestExit; if (roomPath.Count == 1) { nearestExit = start; } else { nearestExit = GetNearestExit(roomPath); } Tile targetTile = null; float distance = float.MaxValue; foreach (Furniture furniture in World.Current.FurnitureManager.Where(furniture => furniture.Type == type)) { if (Vector3.Distance(nearestExit.Vector3, furniture.Tile.Vector3) < distance) { distance = Vector3.Distance(nearestExit.Vector3, furniture.Tile.Vector3); targetTile = furniture.Tile; } } return(FindPathToTile(start, targetTile)); } else { // Since we don't have a roomPath, someone's done something weird, like a room of doors, so just use Dijkstra to find our way Path_AStar resolver = new Path_AStar(World.Current, start, GoalFurnitureEvaluator(type), DijkstraDistance()); List <Tile> path = resolver.GetList(); return(path); } }
/// <summary> /// Finds the path to tile. /// </summary> /// <returns>The path to tile.</returns> /// <param name="start">Start tile.</param> /// <param name="end">Final tile.</param> /// <param name="adjacent">If set to <c>true</c> adjacent tiles can be targetted.</param> public static List <Tile> FindPathToTile(Tile start, Tile end, bool adjacent = false) { if (start == null || end == null) { return(null); } Path_AStar resolver = new Path_AStar(World.Current, start, GoalTileEvaluator(end, adjacent), ManhattanDistance(end)); List <Tile> path = resolver.GetList(); if (adjacent) { DebugLogIf(path.Count > 0, "FindPathToTile adjacent from: {0}, to: {1}, found {2} [Length: {3}", start, end, path.Last(), path.Count); } else { DebugLogIf(path.Count > 0, "FindPathToTile from: " + start.X + "," + start.Y + ", to: " + end.X + "," + end.Y + " found: " + path.Last().X + "," + path.Last().Y + " [Length: " + path.Count + "]"); } DebugLogIf(path == null, "Failed to find path to tile {0}", start); return(path); }
private void Update_DoMovement(float deltaTime) { if (CurrTile == DestTile) { // We're already were we want to be. pathAStar = null; IsWalking = false; VisualPath.Instance.RemoveVisualPoints(name); return; } if (nextTile == null || nextTile == CurrTile) { // Get the next tile from the pathfinder. if (pathAStar == null || pathAStar.Length() == 0) { // Generate a path to our destination. // This will calculate a path from current tile to destination tile. pathAStar = new Path_AStar(World.Current, CurrTile, DestTile); if (pathAStar.Length() == 0) { Debug.ULogErrorChannel("Character", "Path_AStar returned no path to destination!"); AbandonJob(false); return; } // Let's ignore the first tile, because that's the tile we're currently in. nextTile = pathAStar.Dequeue(); } if (IsSelected) { VisualPath.Instance.SetVisualPoints(name, pathAStar.GetList()); } IsWalking = true; // Grab the next waypoint from the pathing system! nextTile = pathAStar.Dequeue(); if (nextTile == CurrTile) { IsWalking = false; } } if (nextTile.IsEnterable() == Enterability.Never) { //// Most likely a wall got built, so we just need to reset our pathfinding information. //// FIXME: Ideally, when a wall gets spawned, we should invalidate our path immediately, //// so that we don't waste a bunch of time walking towards a dead end. //// To save CPU, maybe we can only check every so often? //// Or maybe we should register a callback to the OnTileChanged event? //// Debug.ULogErrorChannel("FIXME", "A character was trying to enter an unwalkable tile."); nextTile = null; // our next tile is a no-go pathAStar = null; // clearly our pathfinding info is out of date. return; } else if (nextTile.IsEnterable() == Enterability.Soon) { // We can't enter the NOW, but we should be able to in the // future. This is likely a DOOR. // So we DON'T bail on our movement/path, but we do return // now and don't actually process the movement. return; } CharacterFacing(); // At this point we should have a valid nextTile to move to. // What's the total distance from point A to point B? // We are going to use Euclidean distance FOR NOW... // But when we do the pathfinding system, we'll likely // switch to something like Manhattan or Chebyshev distance float distToTravel = Mathf.Sqrt( Mathf.Pow(CurrTile.X - nextTile.X, 2) + Mathf.Pow(CurrTile.Y - nextTile.Y, 2)); // How much distance can be travel this Update? float distThisFrame = speed / nextTile.MovementCost * deltaTime; // How much is that in terms of percentage to our destination? float percThisFrame = distThisFrame / distToTravel; // Add that to overall percentage travelled. movementPercentage += percThisFrame; if (movementPercentage >= 1) { // We have reached our destination //// TODO: Get the next tile from the pathfinding system. //// If there are no more tiles, then we have TRULY //// reached our destination. CurrTile = nextTile; movementPercentage = 0; // FIXME? Do we actually want to retain any overshot movement? } }
public static List <Tile> FindPath(Tile start, GoalEvaluator isGoal, PathfindingHeuristic costHeuristic) { Path_AStar resolver = new Path_AStar(World.Current, start, isGoal, costHeuristic); return(resolver.GetList()); }