public Level(int width, int height, Texture2D bg_texture, Texture2D wall_texture, List<GameUnit> bosses) { Width = width; Height = height; BackgroundTexture = bg_texture; Map = new Map(width, height, wall_texture); Bosses = bosses; NumBosses = bosses.Count; BossesDefeated = 0; }
/* * Process collisions for every unit */ public void ProcessCollisions(int x, int y, Map map) { List<Point> adjacent = getAdjacent(new Point(x, y)); foreach (GameUnit unit in cellGrid[y, x]) { foreach (Point loc in adjacent) { if (loc.Y > 0 && loc.X > 0 && loc.Y < cellGrid.GetLength(0) && loc.X < cellGrid.GetLength(1) && cellGrid[loc.Y, loc.X] != null) { foreach (GameUnit other in cellGrid[loc.Y, loc.X]) { if (unit != other) { //CheckUnitCollision(unit, other); } } } } //CheckWallCollision(unit, map); } }
/* * Handle a collision between a unit and wall */ public void CheckWallCollision(GameUnit unit, Map map) { }
/* * A* to target */ private bool findTarget(GameUnit unit, Vector2 target, Map map, int limit) { List<Vector2> path = Pathfinder.findPath(map, unit.Position, unit.Target, limit, false); // Set the next move to the last node in the path with no obstacles in the way if (path != null) { for (int i = path.Count - 1; i > 0; i--) { if (!map.rayCastHasObstacle(unit.Position, path[i], unit.Size / 2)) { unit.NextMove = path[i]; unit.Lost = false; return true; } } return true; } else { double d = unit.distance(Player); if (unit.Faction == UnitFaction.ALLY && (Player == null || unit.distance(Player) > LOST_ALLY_DISTANCE)) { unit.Lost = true; } return false; } }
/* * Use point location field to find the player (NOT IN USE) */ private Vector2 findMoveToPlayer(GameUnit unit, Map map) { return playerLocationField[(int)unit.Position.Y / Map.TILE_SIZE, (int)unit.Position.X / Map.TILE_SIZE]; }
/* * Handle a collision between a unit and wall */ public void CheckWallCollision(GameUnit unit, Map map) { List<Vector2> dirs = new List<Vector2>(); dirs.Add(new Vector2(0, 1)); dirs.Add(new Vector2(1, 0)); dirs.Add(new Vector2(0, -1)); dirs.Add(new Vector2(-1, 0)); dirs.Add(new Vector2(1, 1)); dirs.Add(new Vector2(1, -1)); dirs.Add(new Vector2(-1, 1)); dirs.Add(new Vector2(-1, -1)); foreach (Vector2 dir in dirs) { if(!map.canMoveToWorldPos(unit.Position + dir * unit.Size/2)) { int i = 0; while (i++ < unit.Size && !map.canMoveToWorldPos(unit.Position + dir * unit.Size/2)) { unit.Position -= dir; } } } }
/* * Process collisions for every unit */ public void ProcessCollisions(GameUnit unit, Map map) { if (unit == null) return; int x_index = (int)MathHelper.Clamp((unit.Position.X / CELL_SIZE), 0, cellGrid.GetLength(1) - 1); int y_index = (int)MathHelper.Clamp((unit.Position.Y / CELL_SIZE), 0, cellGrid.GetLength(0) - 1); List<Point> adjacent = getAdjacent(new Point(x_index, y_index)); foreach (Point loc in adjacent) { foreach (GameUnit other in cellGrid[loc.Y, loc.X]) { // Don't check collision for the same units or if they are in the same position (will crash) if (unit != other && unit.Position != other.Position && !unit.Ghost) { CheckUnitCollision(unit, other); } } } CheckWallCollision(unit, map); }
/* * Finds the tile based path from start to end, given in world coordinates */ public static List<Vector2> findPath(Map map, Vector2 start, Vector2 end, int limit, bool exploreAll) { if (!map.canMoveToWorldPos(end)) { return null; } BinaryHeap<PathNode> node_queue = new BinaryHeap<PathNode>(new NodeCompararer()); // use comparator HashSet<PathNode> visited = new HashSet<PathNode>(); Vector2 mapStart = map.translateWorldToMap(start); Vector2 mapEnd = map.translateWorldToMap(end); Point startPoint = new Point((int)mapStart.X, (int)mapStart.Y); Point endPoint = new Point((int)mapEnd.X, (int)mapEnd.Y); PathNode startNode = new PathNode(startPoint); startNode.G_score = 0; startNode.H_score = calculateHeuristic(startPoint, endPoint); node_queue.Insert(startNode); while (node_queue.Count > 0) { PathNode current = node_queue.RemoveRoot(); // O(logn) PathNode current2 = getMin(node_queue.GetList()); if (!exploreAll && current.Pos.Equals(endPoint)) { return constructPath(current); } if (current.G_score + 1 > limit) // Don't explore tiles too far { continue; } visited.Add(current); List<Point> adj = getAdjacent(current.Pos); foreach (Point position in adj) { if (visited.Contains(new PathNode(position)) || !map.canMoveTo(position.X, position.Y)) { continue; } PathNode node = nodeAtPosition(node_queue, position); // O(n) if (node != null && current.G_score + 1 < node.G_score) { node.G_score = current.G_score + 1; node.Parent = current; node_queue.RemoveNode(node); // O(n) node_queue.Insert(node); // O(logn) } else if(node == null) { node = new PathNode(position); node.G_score = current.G_score + 1; node.H_score = calculateHeuristic(node.Pos, endPoint); node.Parent = current; node_queue.Insert(node); // O(logn) } } } if (!exploreAll) return null; // Populate the point location map, initialize with (-1, -1) pointLocMap = new Vector2[map.HeightTiles, map.WidthTiles]; for (int i = 0; i < pointLocMap.GetLength(0); i++) { for (int j = 0; j < pointLocMap.GetLength(1); j++) { pointLocMap[i, j] = new Vector2(-1, -1); } } pointLocMap[(int)mapStart.Y, (int)mapStart.X] = mapStart; foreach(PathNode node in visited) { if (pointLocMap[node.Pos.Y, node.Pos.X] == new Vector2(-1, -1)) { Vector2 nodePos = new Vector2(node.Pos.X * Map.TILE_SIZE + Map.TILE_SIZE/2, node.Pos.Y * Map.TILE_SIZE + Map.TILE_SIZE/2); if (map.rayCastHasObstacle(nodePos, end, Map.TILE_SIZE/3)) { pointLocMap[node.Pos.Y, node.Pos.X] = new Vector2(node.Parent.Pos.X, node.Parent.Pos.Y); } else { pointLocMap[node.Pos.Y, node.Pos.X] = mapEnd; } //collapseBlockedPaths(node, map); } } return null; }
/* * Iterates through positions with obstacles to target of pointLocMap (player position), and * points them to the next position without an obstacle. * * Vector2 end is given in tile coordinates * Assumes the 0,0 tile will be a wall, so it doesn't count as a position */ private static void collapseBlockedPaths(PathNode start, Map map) { if (start.Parent == null) return; if (start.Pos.X == 5 && start.Pos.Y == 4) { int a = 0; } Vector2 startPos = new Vector2(start.Pos.X, start.Pos.Y); PathNode cur = start; Vector2 curPos = new Vector2(cur.Pos.X, cur.Pos.Y); Vector2 prevPos = new Vector2(-1, -1); List<Vector2> positionsInPath = new List<Vector2>(); while(!map.rayCastHasObstacle( startPos*Map.TILE_SIZE + new Vector2(Map.TILE_SIZE/2, Map.TILE_SIZE/2), curPos*Map.TILE_SIZE + new Vector2(Map.TILE_SIZE/2, Map.TILE_SIZE), Map.TILE_SIZE/2-5)) { positionsInPath.Add(curPos); cur = cur.Parent; if (cur == null) { break; } curPos = new Vector2(cur.Pos.X, cur.Pos.Y); } foreach (Vector2 pos in positionsInPath) { pointLocMap[(int)pos.Y, (int)pos.X] = curPos; } }