Example #1
0
 public void AddOccupant(ITileOccupant occupant)
 {
     if (_occupants.Contains(occupant))
     {
         return;
     }
     _occupants.Add(occupant);
 }
    private static bool IsTileTraversable(ITileInfo tileInfo, ITileOccupant occupant, int traversableThreshold)
    {
        bool isTraversable = tileInfo != null;

        isTraversable |= traversableThreshold > tileInfo.Occupants.Count;
        isTraversable |= tileInfo.ContainsOccupant(occupant);
        isTraversable &= !tileInfo.Data.IsSolid;
        return(isTraversable);
    }
Example #3
0
    public void RemoveOccupant(IntVector3 position, ITileOccupant occupant)
    {
        if (!IsWithinMap(position))
        {
            CustomLogger.Error(nameof(LevelDataManager), $"Position {position} is out of bounds!");
            return;
        }
        ITileInfo tileInfo = _tiles[position.x][position.y];

        tileInfo.RemoveOccupant(occupant);
    }
    public static PathStatus GetPathToDestination(IntVector3 startPosition,
                                                  IntVector3 targetDestination,
                                                  List <IntVector3> path,
                                                  ITileOccupant occupant,
                                                  int traversableThreshold)
    {
        // setup for path finding
        path?.Clear();
        List <TileNode>   toBeVisited    = new List <TileNode>();
        List <IntVector3> alreadyVisited = new List <IntVector3>();

        // validate the given destination first
        if (!LevelDataManager.Instance.IsWithinMap(targetDestination))
        {
            CustomLogger.Warn(nameof(MapService), $"Target Destination {targetDestination} is out of bounds!");
            return(PathStatus.Invalid);
        }
        ITileInfo startingTileInfo = LevelDataManager.Instance.GetTileAt(targetDestination.x, targetDestination.y);

        if (startingTileInfo != null && (startingTileInfo.Occupants.Count > traversableThreshold || startingTileInfo.Data.IsSolid))
        {
            CustomLogger.Warn(nameof(MapService), $"Target Destination {targetDestination} Invalid!");
            return(PathStatus.Invalid);
        }

        int startX  = startPosition.x;
        int startY  = startPosition.y;
        int targetX = targetDestination.x;
        int targetY = targetDestination.y;

        toBeVisited.Clear();
        alreadyVisited.Clear();

        // this current node will be the first node that we check
        TileNode current = new TileNode()
        {
            X = startX,
            Y = startY,
            DistanceFromStart = 0,
            TotalCost         = 0
        };

        toBeVisited.Add(current);
        int count = 0;

        while (toBeVisited.Count != 0)
        {
            // get current node
            count++;
            current = GetLowestCostNode(toBeVisited);
            // remove from to be visited
            toBeVisited.Remove(current);

            // if we've hit our destination
            if (current.X == targetX && current.Y == targetY)
            {
                while (current.Parent != null)
                {
                    path.Insert(0, new IntVector3(current.X, current.Y));
                    current = current.Parent;
                }
                return(PathStatus.Complete);
            }

            // checks all directions for valid, unexplored tiles
            for (int i = 0; i < _directions.Length; i++)
            {
                int        dirX      = _directions[i].x;
                int        dirY      = _directions[i].y;
                int        neighborX = current.X + dirX;
                int        neighborY = current.Y + dirY;
                IntVector3 neighbor  = new IntVector3(neighborX, neighborY);
                // check if we've already looked here
                if (ContainsIntVector3(neighborX, neighborY, alreadyVisited))
                {
                    continue;
                }
                // check if this tile is on the map
                if (!LevelDataManager.Instance.IsWithinMap(neighbor))
                {
                    continue;
                }
                ITileInfo neighborTileInfo = LevelDataManager.Instance.GetTileAt(neighborX, neighborY);
                bool      _canTraverse     = IsTileTraversable(neighborTileInfo, occupant, traversableThreshold);

                // if this is a corner piece
                int sumOf = Mathf.Abs(dirX) + Mathf.Abs(dirY);
                if (sumOf == 2 && _canTraverse)
                {
                    // check if adjacent sides are open
                    ITileInfo neighborTileX = LevelDataManager.Instance.GetTileAt(current.X + dirX, current.Y);
                    ITileInfo neighborTileY = LevelDataManager.Instance.GetTileAt(current.X, current.Y + dirY);
                    // check if both tiles are available
                    _canTraverse &= IsTileTraversable(neighborTileX, occupant, traversableThreshold);
                    _canTraverse &= IsTileTraversable(neighborTileY, occupant, traversableThreshold);
                }
                // if this tile is not traversable, ignore it
                if (!_canTraverse)
                {
                    continue;
                }

                int distanceFromStart = DistanceFromStart(startX, startY, neighborX, neighborY);

                // if this node is in "to be visited", check to see if the distance value needs to be updated and skipped
                bool markedToBeVisited = TryGetNode(neighborX, neighborY, toBeVisited, out int toBeVisitedIndex);
                if (markedToBeVisited)
                {
                    TileNode toBeVisitedNode = toBeVisited[toBeVisitedIndex];
                    if (distanceFromStart < toBeVisitedNode.DistanceFromStart)
                    {
                        toBeVisitedNode.DistanceFromStart = distanceFromStart;
                    }
                    // do not add again to the list
                    continue;
                }

                // create a new node and add to open list
                TileNode newNode = new TileNode()
                {
                    X                 = neighborX,
                    Y                 = neighborY,
                    TotalCost         = GetNodeTotalCost(startX, startY, neighborX, neighborY, targetX, targetY),
                    DistanceFromStart = distanceFromStart,
                    Parent            = current
                };
                toBeVisited.Add(newNode);
            }
            alreadyVisited.Add(new IntVector3(current.X, current.Y));

            if (count > NumTriesAbort)
            {
                CustomLogger.Error(nameof(MapService), $"In \"{nameof(GetPathToDestination)}\" Failed to path find to {targetDestination}! Aborting...");
                break;
            }
        }
        return(PathStatus.Invalid);
    }
    public static List <IntVector3> GetTraversableTiles(
        int radius,
        IntVector3 start,
        ITileOccupant occupant,
        int traversableThreshold,
        int minDistance = 0)
    {
        List <TileNode>   toBeVisited        = new List <TileNode>();
        List <IntVector3> alreadyVisited     = new List <IntVector3>();
        List <IntVector3> traversableTargets = new List <IntVector3>();

        if (!LevelDataManager.Instance.IsWithinMap(start))
        {
            CustomLogger.Warn(nameof(MapService), $"Starting position '{start}' is out of bounds!");
            return(traversableTargets);
        }

        TileNode current = new TileNode()
        {
            X = start.x,
            Y = start.y,
            DistanceFromStart = 0
        };

        toBeVisited.Add(current);
        int count = 0;

        while (toBeVisited.Count != 0)
        {
            count++;
            current = toBeVisited[0];
            ITileInfo currentTile = LevelDataManager.Instance.GetTileAt(current.X, current.Y);
            if (current.DistanceFromStart >= minDistance && IsTileTraversable(currentTile, occupant, traversableThreshold))
            {
                traversableTargets.Add(new IntVector3(current.X, current.Y));
            }
            toBeVisited.RemoveAt(0);
            alreadyVisited.Add(new IntVector3(current.X, current.Y));

            for (int i = 0; i < Directions.Length; i++)
            {
                int        dirX      = Directions[i].x;
                int        dirY      = Directions[i].y;
                int        neighborX = current.X + Directions[i].x;
                int        neighborY = current.Y + Directions[i].y;
                IntVector3 neighbor  = new IntVector3(neighborX, neighborY);

                int distanceFromStart = DistanceFromStart(start.x, start.y, neighborX, neighborY);
                if (distanceFromStart > radius)
                {
                    continue;
                }

                if (ContainsIntVector3(neighborX, neighborY, alreadyVisited) || !LevelDataManager.Instance.IsWithinMap(neighbor))
                {
                    continue;
                }

                ITileInfo neighborTileInfo = LevelDataManager.Instance.GetTileAt(neighborX, neighborY);
                bool      _canTraverse     = IsTileTraversable(neighborTileInfo, occupant, traversableThreshold);

                // if this is a corner piece
                int sumOf = Mathf.Abs(dirX) + Mathf.Abs(dirY);
                if (sumOf == 2 && _canTraverse)
                {
                    // check if adjacent sides are open
                    ITileInfo neighborTileX = LevelDataManager.Instance.GetTileAt(current.X + dirX, current.Y);
                    ITileInfo neighborTileY = LevelDataManager.Instance.GetTileAt(current.X, current.Y + dirY);
                    // check if both tiles are available
                    _canTraverse &= IsTileTraversable(neighborTileX, occupant, traversableThreshold);
                    _canTraverse &= IsTileTraversable(neighborTileY, occupant, traversableThreshold);
                }

                if (ContainsNode(neighborX, neighborY, toBeVisited))
                {
                    continue;
                }

                TileNode newNode = new TileNode()
                {
                    X = neighborX,
                    Y = neighborY,
                    DistanceFromStart = distanceFromStart
                };
                toBeVisited.Add(newNode);
            }
            if (count > NumTriesAbort)
            {
                CustomLogger.Error(nameof(MapService), $"{nameof(GetTraversableTiles)} Aborting after {count} steps!");
                break;
            }
        }
        return(traversableTargets);
    }
Example #6
0
 public bool ContainsOccupant(ITileOccupant occupant)
 {
     return(_occupants.Contains(occupant));
 }
Example #7
0
 public void RemoveOccupant(ITileOccupant occupant)
 {
     _occupants.Remove(occupant);
 }