Example #1
0
        protected override Rectangle?SelectNextLot(RectangleIntervalTree placedFragments, SimpleRandom random)
        {
            var boundingRectangle = placedFragments.BoundingRectangle;

            while (_lotSize.Width > boundingRectangle.Width || _lotSize.Height > boundingRectangle.Height)
            {
                _lotSize = new Dimensions((byte)(_lotSize.Width - 1), (byte)(_lotSize.Height - 1));
            }

            while (_lotSize.Contains(MinLotSize))
            {
                // TODO: Optimize using
                // "Polygon Decomposition". Handbook of Computational Geometry. p. 491 or
                // "Graph-Theoretic Solutions to Computational Geometry Problems"
                // https://stackoverflow.com/questions/5919298/algorithm-for-finding-the-fewest-rectangles-to-cover-a-set-of-rectangles-without

                for (var attempt = 0; attempt < LotPlacementAttempts; attempt++)
                {
                    var x1 = (byte)random.Next(boundingRectangle.TopLeft.X,
                                               boundingRectangle.BottomRight.X - _lotSize.Width + 1);
                    var y1 = (byte)random.Next(boundingRectangle.TopLeft.Y,
                                               boundingRectangle.BottomRight.Y - _lotSize.Height + 1);
                    var potentialLot = new Rectangle(new Point(x1, y1), (byte)(_lotSize.Width - 1),
                                                     (byte)(_lotSize.Height - 1));
                    if (!placedFragments.GetOverlapping(potentialLot).Any())
                    {
                        return(potentialLot);
                    }
                }

                _lotSize = new Dimensions((byte)(_lotSize.Width - 1), (byte)(_lotSize.Height - 1));
            }

            return(null);
        }
Example #2
0
 protected abstract Rectangle?SelectNextLot(RectangleIntervalTree placedFragments, SimpleRandom random);
Example #3
0
        protected void PlaceSurroundingFragments(LevelComponent level, List <Room> rooms)
        {
            var manager = level.Entity.Manager;
            var levelBoundingRectangle = level.BoundingRectangle;
            var placedFragments        = new RectangleIntervalTree(levelBoundingRectangle);
            var filledArea             = 0;

            var placedRoom = rooms.FirstOrDefault();

            if (placedRoom != null)
            {
                placedFragments.Insert(placedRoom.BoundingRectangle);
                filledArea += placedRoom.BoundingRectangle.Area;
            }

            var placingConnections = true;

            while (filledArea / (float)levelBoundingRectangle.Area < Coverage && rooms.Count < MaxRoomCount)
            {
                var nextLot = SelectNextLot(placedFragments, level.GenerationRandom);
                if (nextLot == null)
                {
                    throw new InvalidOperationException("No more available lots found");
                }

                // For every existing connection to this level that hasn't been connected yet generate a destination fragment.
                // Then generate up to 3 source fragments, depending on the number of incoming connections
                //     At least 2 to the next branch level if not final
                var danglingConnection = manager.IncomingConnectionsToLevelRelationship[level.EntityId]
                                         .Select(c => c.Connection).FirstOrDefault(c => c.TargetLevelX == null);
                placingConnections = placingConnections &&
                                     (danglingConnection != null ||
                                      manager.ConnectionsToLevelRelationship[level.EntityId]
                                      .Count(c => c.Connection.TargetLevelX == null) < 3 ||
                                      (level.Branch.Length > level.Depth &&
                                       manager.ConnectionsToLevelRelationship[level.EntityId]
                                       .Select(c => manager.FindEntity(c.Connection.TargetLevelId).Level)
                                       .Count(l =>
                                              l.BranchName == level.BranchName &&
                                              l.Depth == level.Depth + 1) < 2));
                var sortedFragments = placingConnections
                    ? level.GenerationRandom.WeightedOrder(
                    ConnectingMapFragment.Loader.GetAsList(),
                    f => f.GetWeight(level, nextLot.Value, danglingConnection))
                    : (IEnumerable <MapFragment>)level.GenerationRandom.WeightedOrder(
                    NormalMapFragment.Loader.GetAsList(),
                    f => f.GetWeight(level, nextLot.Value));

                placedRoom = TryPlace(level, nextLot.Value, sortedFragments);
                if (placedRoom == null)
                {
                    if (placingConnections)
                    {
                        placingConnections = false;
                        continue;
                    }

                    throw new InvalidOperationException("No suitable fragments");
                }

                rooms.Add(placedRoom);
                placedFragments.Insert(placedRoom.BoundingRectangle);
                filledArea += placedRoom.BoundingRectangle.Area;
            }

            // TODO: Fill the empty space with snapping fragments and connect them to overwritable fragments

            if (rooms.Count > 1)
            {
                // TODO: Perf: use a different data structure
                var connectedRooms = new List <Room> {
                    rooms.First()
                };
                var unconnectedRooms = new List <Room>(rooms.Skip(1).Where(r => r.DoorwayPoints.Count > 0));
                while (unconnectedRooms.Count > 0)
                {
                    var randomConnectedRoom  = level.GenerationRandom.Pick(connectedRooms);
                    var unconnectedRoom      = randomConnectedRoom.GetOrthogonallyClosest(unconnectedRooms);
                    var closestConnectedRoom = unconnectedRoom.GetOrthogonallyClosest(connectedRooms);
                    if (!Connect(unconnectedRoom, closestConnectedRoom))
                    {
                        throw new InvalidOperationException("Couldn't connect all rooms");
                    }

                    connectedRooms.Add(unconnectedRoom);
                    unconnectedRooms.Remove(unconnectedRoom);
                }
            }
        }
Example #4
0
 protected override Rectangle?SelectNextLot(RectangleIntervalTree placedFragments, SimpleRandom random) => null;