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); }
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); }
public bool ContainsOccupant(ITileOccupant occupant) { return(_occupants.Contains(occupant)); }
public void RemoveOccupant(ITileOccupant occupant) { _occupants.Remove(occupant); }