Esempio n. 1
0
    private void _connectTraversableTiles(Godot.Collections.Array tiles)
    {
        foreach (Vector2 tile in tiles)
        {
            // Add all neighbors
            for (int indexX = -1; indexX < 2; indexX++)
            {
                for (int indexY = -1; indexY < 2; indexY++)
                {
                    Vector2 targetTile = new Vector2(tile.x + indexX, tile.y + indexY);
                    int     toId       = getPointID((int)targetTile.x, (int)targetTile.y);
                    int     fromId     = getPointID((int)tile.x, (int)tile.y);

                    if (tile == targetTile || !_aStar.HasPoint(toId))
                    {
                        // No need to add tile as it is the same
                        continue;
                    }

                    // Caculate if diagonal point can be used
                    // (this is to avoid to given a diagonal path to agent, but agent cannot pass as vertical/horizontal has obstacles)

                    // Upper left/right diagonal (-1,1), (1,1)
                    // which need (-1,0) (horizontal), (0,1) (veritcal), (1,0) (horizontal)

                    // Bottom left/right diagonal (-1,-1), (1,-1)
                    // which need (-1,0) (horizontal), (0,-1) (veritcal), (1,0) (horizontal)

                    // this is to avoid stuck on corner
                    if (indexX != 0 && indexY != 0)
                    {
                        int horizaontalId = getPointID((int)tile.x + indexX, (int)tile.y);
                        int verticalId    = getPointID((int)tile.x, (int)tile.y + indexY);

                        // Upper diaonal connection depend on if there is obstacle for vertical/horizontal neighbors
                        // If there are obstacles (i.e. point not exist, then not connect it)
                        if (!_aStar.HasPoint(horizaontalId) || !_aStar.HasPoint(verticalId))
                        {
                            continue;
                        }
                    }

                    if (!_aStar.ArePointsConnected(fromId, toId))
                    {
                        // Debug code
                        if (debug)
                        {
                            Line2D    line2d = new Line2D();
                            Vector2[] points = { (Vector2)_tilestoWorld[fromId], (Vector2)_tilestoWorld[toId] };
                            line2d.Points = points;
                            _tileMap.AddChild(line2d);
                        }
                        _aStar.ConnectPoints(fromId, toId, true);
                    }
                }
            }
        }
    }
Esempio n. 2
0
        private void ConnectCornerCells()
        {
            // find all cells with a higher (lower on the screen) y value AND an x value to the right (if right corner) or to the left (if left corner) AND within the max distance
            foreach (var cornerCell in _astarCornerCells)
            {
                IEnumerable <AstarCell> cellsToConnect;
                if (cornerCell.IsLeftCorner)
                {
                    cellsToConnect = _astarCells
                                     .Where(cell =>
                                            cell.Position.y > cornerCell.Position.y &&
                                            cell.Position.x < cornerCell.Position.x - 2 &&
                                            cell.Position.DistanceSquaredTo(cornerCell.Position) <= MAX_CELL_DISTANCE * MAX_CELL_DISTANCE
                                            );
                }
                else
                {
                    cellsToConnect = _astarCells
                                     .Where(cell =>
                                            cell.Position.y > cornerCell.Position.y &&
                                            cell.Position.x > cornerCell.Position.x + 2 &&
                                            cell.Position.DistanceSquaredTo(cornerCell.Position) <= MAX_CELL_DISTANCE * MAX_CELL_DISTANCE
                                            );
                }

                // for each cell that matches the above conditions
                // create a new astar cell at the corner position with a weight equal to the distance of the cell to connect to
                // then connect the two cells together
                foreach (var toConnectCell in cellsToConnect)
                {
                    var dist = toConnectCell.Position.DistanceTo(cornerCell.Position);
                    _astar.AddPoint(_astarId, cornerCell.Position, dist);
                    _astar.ConnectPoints(toConnectCell.Id, _astarId, true);

                    // connect new corner cell to "real" corner cell to complete the loop
                    if (_positionToCell.ContainsKey(cornerCell.Position))
                    {
                        _astar.ConnectPoints(_positionToCell[cornerCell.Position].Id, _astarId, true);
                    }
                    _astarId++;
                }
            }
        }
Esempio n. 3
0
    // 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));
    }
Esempio n. 4
0
    //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);
    }