예제 #1
0
        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);
        }
예제 #2
0
        /// <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);
            }
        }
예제 #3
0
        /// <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);
        }
예제 #4
0
        /// <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);
        }
예제 #5
0
        /// <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);
            }
        }
예제 #6
0
        /// <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);
        }
예제 #7
0
    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?
        }
    }
예제 #8
0
        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());
        }