// Adds both secondary room and corridor tile positions to `_data`. Secondary rooms are the ones // intersecting the corridors. private void AddCorridors() { //Stores existing connections in its keys. var connected = new Dictionary <Vector2, object>(); //Checks if points are connected by a corridor. If not, adds a corridor. foreach (int point1Id in _path.GetPoints()) { foreach (var point2Id in _path.GetPointConnections(point1Id)) { var point1 = _path.GetPointPosition(point1Id); var point2 = _path.GetPointPosition(point2Id); if (connected.ContainsKey(new Vector2(point1Id, point2Id))) { continue;; } point1 = Level.WorldToMap(point1); point2 = Level.WorldToMap(point2); AddCorridor((int)point1.x, (int)point2.x, (int)point1.y, Vector2.Axis.X); AddCorridor((int)point1.x, (int)point2.x, (int)point2.y, Vector2.Axis.Y); //Stores the connection between point 1 and 2. connected[new Vector2(point1Id, point2Id)] = null; connected[new Vector2(point2Id, point1Id)] = null; } } }
// Called every time stabilizes (mode changes to RigidBody2D.MODE_STATIC). // // Once all rooms have stabilized it calculates a playable dungeon `_path` using the MST // algorithm. Based on the calculated `_path`, it populates `_data` with room and corridor tile // positions. // // It emits the "rooms_placed" signal when it finishes so we can begin the tileset placement. private void _on_Room_sleeping_state_changed() { GD.Print("_on_Room_sleeping_state_changed"); _sleepingRooms++; if (_sleepingRooms < MaxRooms) { return; } var mainRooms = new List <Room>(); var mainRoomsPositions = new List <Vector2>(); foreach (Room room in Rooms.GetChildren()) { if (IsMainRoom(room)) { mainRooms.Add(room); mainRoomsPositions.Add(room.Position); } } _path = Utils.MST(mainRoomsPositions); foreach (int point1Id in _path.GetPoints()) { foreach (int point2Id in _path.GetPoints()) { if (point1Id != point2Id && !_path.ArePointsConnected(point1Id, point2Id) && _rng.Randf() < ReconnectionFactor) { _path.ConnectPoints(point1Id, point2Id); } } } foreach (Room room in mainRooms) { AddRoom(room); } AddCorridors(); SetProcess(false); EmitSignal(nameof(RoomsPlaced)); }
//Calculates the Minimum Spanning Tree (MST) for given points and returns an `AStar2D` graph using Prim's algorithm. // https://en.wikipedia.org/wiki/Prim%27s_algorithm // https://en.wikipedia.org/wiki/Minimum_spanning_tree public static AStar2D MST(List <Vector2> pointsList) { var result = new AStar2D(); var firstPoint = pointsList.LastOrDefault(); //Start from an arbitrary point in the list of points result.AddPoint(result.GetAvailablePointId(), firstPoint); pointsList.Remove(firstPoint); //Loop through all points, erasing them as we connect them. while (pointsList.Any()) { var currentPosition = Vector2.Zero; var minPosition = Vector2.Zero; var minDistance = float.PositiveInfinity; foreach (int point1Id in result.GetPoints()) { //Compare each point added to the Astar2D graph to each remaining point to find the closest one var point1Position = result.GetPointPosition(point1Id); foreach (var point2Position in pointsList) { var distance = point1Position.DistanceTo(point2Position); if (minDistance > distance) { //We use the variables to store the coordinates of the closest point. //We have to loop over all points to ensure it's the closest. currentPosition = point1Position; minPosition = point2Position; minDistance = distance; } } } //Connect the point closest to the "current position" with our new point var pointId = result.GetAvailablePointId(); result.AddPoint(pointId, minPosition); result.ConnectPoints(result.GetClosestPoint(currentPosition), pointId); pointsList.Remove(minPosition); } return(result); }
public void UpdateNavigationMap() { foreach (int pointID in _aStar.GetPoints()) { _aStar.SetPointDisabled(pointID, false); _gridRects[pointID].Color = _enableColor; } Godot.Collections.Array obstacles = GetTree().GetNodesInGroup("Obstacles"); foreach (Node2D obstacle in obstacles) { if (obstacle is TileMap) { TileMap tileMap = (TileMap)obstacle; foreach (Vector2 tile in tileMap.GetUsedCells()) { int tileID = getPointID((int)tile.x, (int)tile.y); if (_aStar.HasPoint(tileID)) { _aStar.SetPointDisabled(tileID, true); _gridRects[tileID].Color = _disableColor; } } } else if (obstacle is Agent) { Vector2 tile = _tileMap.WorldToMap(obstacle.GlobalPosition); int tileID = getPointID((int)tile.x, (int)tile.y); if (_aStar.HasPoint(tileID)) { _aStar.SetPointDisabled(tileID, true); _gridRects[tileID].Color = _disableColor; } } } }