Esempio n. 1
0
        /// Randomly turns some [wall] tiles into [floor] and vice versa.
        private void Erode(int iterations, TileType floor = TileType.Floor, TileType wall = TileType.Wall)
        {
            var bounds = Level.Bounds.Deflate();

            for (var i = 0; i < iterations; i++)
            {
                // TODO: This way this works is super inefficient. Would be better to
                // keep track of the floor tiles near open ones and choose from them.
                var pos = bounds.PickRandom();

                if (GetTile(pos) != wall)
                {
                    continue;
                }

                // Keep track of how many floors we're adjacent too. We will only erode
                // if we are directly next to a floor.
                var floors = Direction.All.Count(dir => GetTile(pos + dir) == floor);

                // Prefer to erode tiles near more floor tiles so the erosion isn't too
                // spiky.
                if (floors < 2)
                {
                    continue;
                }

                if (Randomizer.ChanceIn(9 - floors))
                {
                    SetTile(pos, floor);
                }
            }
        }
Esempio n. 2
0
        private void AddJunction(Vector pos)
        {
            var tile = Randomizer.ChanceIn(4) ? (Randomizer.ChanceIn(3) ? TileType.OpenDoor : TileType.Floor) : TileType.ClosedDoor;

            SetTile(pos, tile);
        }
Esempio n. 3
0
        private void ConnectRegions()
        {
            // Find all of the tiles that can connect two (or more) regions.
            var connectorRegions = new Dictionary <Vector, HashSet <int> >();

            foreach (var pos in Bounds.Deflate())
            {
                // Can't already be part of a region.
                if (GetTile(pos) != TileType.Wall)
                {
                    continue;
                }

                var regions    = new HashSet <int>();
                var neighbours = Direction.Cardinal
                                 .Select(dir => pos + dir)
                                 .Where(p => Bounds.Contains(p));

                foreach (var neighbour in neighbours)
                {
                    regions.Add(regionMap[neighbour.X, neighbour.Y]);
                }
                if (regions.Count < 2)
                {
                    continue;
                }
                connectorRegions[pos] = regions;
            }

            var connectors = connectorRegions.Keys.ToList();

            // Keep track of which regions have been merged. This maps an original
            // region index to the one it has been merged to.
            var merged      = new Dictionary <int, int>();
            var openRegions = new HashSet <int>();

            for (var i = 0; i <= currentRegion; i++)
            {
                merged[i] = i;
                openRegions.Add(i);
            }

            // Keep connecting regions until we're down to one.
            while (openRegions.Count > 1)
            {
                var connector = connectors.PickRandom();
                if (connector == null)
                {
                    break;
                }

                // Carve the connection.
                AddJunction(connector);

                // Merge the connected regions. We'll pick one region (arbitrarily) and
                // map all of the other regions to its index.
                var mRegions = connectorRegions[connector]
                               .Select(region => merged[region]).ToList();
                var dest    = mRegions.First();
                var sources = mRegions.Skip(1).ToList();

                // Merge all of the affected regions. We have to look at *all* of the
                // regions because other regions may have previously been merged with
                // some of the ones we're merging now.
                for (var i = 0; i <= currentRegion; i++)
                {
                    if (sources.Contains(merged[i]))
                    {
                        merged[i] = dest;
                    }
                }

                // The sources are no longer in use.
                openRegions.RemoveWhere(i => sources.Contains(i));

                // Remove any connectors that aren't needed anymore.
                connectors.RemoveAll(pos => {
                    // Don't allow connectors right next to each other.
                    if ((connector - pos).Distance < 2)
                    {
                        return(true);
                    }

                    // If the connector no long spans different regions, we don't need it.
                    var regions = new HashSet <int>(connectorRegions[pos].Select(region => merged[region]));
                    if (regions.Count > 1)
                    {
                        return(false);
                    }

                    // This connecter isn't needed, but connect it occasionally so that the
                    // dungeon isn't singly-connected.
                    if (Randomizer.ChanceIn(extraConnectorChance))
                    {
                        AddJunction(pos);
                    }

                    return(true);
                });
            }
        }