예제 #1
0
 private void FillEmptyCellsWithWalls(RandomDungeon dungeon)
 {
     for (int x = 0; x < dungeon.width; ++x)
     {
         for (int y = 0; y < dungeon.height; ++y)
         {
             if (dungeon.TileType(x, y) == RandomDungeonTileData.EMPTY_TILE)
             {
                 dungeon.ChangeTileType(x, y, RandomDungeonTileData.WALL_TILE);
             }
         }
     }
 }
예제 #2
0
        private void EnforceWallHeight(RandomDungeon dungeon)
        {
            // Add a bottom layer of walls
            for (int x = 0; x < dungeon.width; ++x)
            {
                for (int y = dungeon.height - 2; y >= 0; --y)
                {
                    if (dungeon.TileType(x, y) == RandomDungeonTileData.WALL_TILE && dungeon.TileType(x, y + 1) == RandomDungeonTileData.EMPTY_TILE &&
                        (y - 1 < 0 || dungeon.TileType(x, y - 1) != RandomDungeonTileData.WALL_TILE))
                    {
                        dungeon.ChangeTileType(x, y + 1, RandomDungeonTileData.WALL_TILE);
                    }
                }
            }

            for (int x = 0; x < dungeon.width; ++x)
            {
                for (int y = dungeon.height - 2; y >= 0; --y)
                {
                    if (dungeon.TileType(x, y) == RandomDungeonTileData.EMPTY_TILE &&
                        (y - 1 < 0 || dungeon.TileType(x, y - 1) == RandomDungeonTileData.WALL_TILE) &&
                        ((x - 1 >= 0 && dungeon.TileType(x - 1, y) == RandomDungeonTileData.WALL_TILE) || (x + 1 < dungeon.width && dungeon.TileType(x + 1, y) == RandomDungeonTileData.WALL_TILE)))
                    {
                        dungeon.ChangeTileType(x, y + 1, RandomDungeonTileData.WALL_TILE);
                    }
                }
            }

            for (int x = 0; x < dungeon.width; ++x)
            {
                for (int y = 0; y < dungeon.height; ++y)
                {
                    int  tile      = dungeon.TileType(x, y);
                    bool wallBelow = (y < dungeon.height - 1 && dungeon.TileType(x, y + 1) == RandomDungeonTileData.WALL_TILE);

                    if (tile == RandomDungeonTileData.EMPTY_TILE)
                    {
                        if (wallBelow)
                        {
                            dungeon.ChangeTileType(x, y, RandomDungeonTileData.WALL_TILE);
                        }
                    }
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Given the current progress of map generation, generates a random dungeon.
        /// This is only exposed as public for demonstration purposes when we want to show the
        /// dungeon being generated dynamically.
        /// </summary>
        /// <param name="generationData"></param>
        /// <returns></returns>
        public RandomDungeon GenerateRandomDungeonFromCurrentProgress(RandomDungeonGenerationData generationData, Dictionary <Vector2Int, RandomDungeonTileData> scratch = null)
        {
            RandomDungeon dungeon = GenerateDungeonObjectFromScratchPad(scratch != null ? scratch : mRoomScratch);

            CloseExitsToNowhere(dungeon);

            if (generationData.enforceTwoTileHighWalls)
            {
                EnforceWallHeight(dungeon);
            }

            if (generationData.fillEmptyCellsWithWalls)
            {
                FillEmptyCellsWithWalls(dungeon);
            }

            return(dungeon);
        }
예제 #4
0
        /// <summary>
        /// After map generation is finished, this will close off all the exits that don't lead to
        /// another room.
        /// </summary>
        /// <param name="dungeon"></param>
        private void CloseExitsToNowhere(RandomDungeon dungeon)
        {
            if (stopCloseExitsToNowhere)
            {
                return;
            }

            int exitPasses = 2; // should be equal the wall height

            for (int exitPass = 0; exitPass < exitPasses; ++exitPass)
            {
                for (int x = 0; x < dungeon.width; ++x)
                {
                    for (int y = 0; y < dungeon.height; ++y)
                    {
                        int tile = dungeon.TileType(x, y);
                        if (tile == RandomDungeonTileData.EXIT_TILE)
                        {
                            if (dungeon.NumWalkableNeighbors(x, y) <= 1)
                            {
                                dungeon.ChangeTileType(x, y, RandomDungeonTileData.WALL_TILE);
                            }
                        }
                    }
                }
            }

            for (int x = 0; x < dungeon.width; ++x)
            {
                for (int y = 0; y < dungeon.height; ++y)
                {
                    int tile = dungeon.TileType(x, y);
                    if (tile == RandomDungeonTileData.EMPTY_TILE)
                    {
                        if (dungeon.NumWalkableNeighbors(x, y) >= 1)
                        {
                            dungeon.ChangeTileType(x, y, RandomDungeonTileData.WALL_TILE);
                        }
                    }
                }
            }
        }
예제 #5
0
        /// <summary>
        /// Generates the RandomDungeon object from the scratchpad, creating the final 2d array that
        /// represents the dungeon in the process.
        /// </summary>
        /// <returns></returns>
        private RandomDungeon GenerateDungeonObjectFromScratchPad(Dictionary <Vector2Int, RandomDungeonTileData> scratch)
        {
            int minX = int.MaxValue,
                minY = int.MaxValue,
                maxX = int.MinValue,
                maxY = int.MinValue;

            foreach (Vector2Int pos in scratch.Keys)
            {
                minX = Mathf.Min(minX, pos.x);
                minY = Mathf.Min(minY, pos.y);
                maxX = Mathf.Max(maxX, pos.x);
                maxY = Mathf.Max(maxY, pos.y);
            }

            int           padding = 2;
            int           width   = maxX - minX + 1 + padding * 2;
            int           height  = maxY - minY + 1 + padding * 2;
            RandomDungeon dungeon = new RandomDungeon(width, height);

            foreach (KeyValuePair <Vector2Int, RandomDungeonTileData> pair in scratch)
            {
                int x = pair.Key.x - minX + padding;
                int y = pair.Key.y - minY + padding;
                dungeon.SetData(x, y, pair.Value);
            }

            for (int i = 0; i < mPrimaryPathPositions.Count; ++i)
            {
                mPrimaryPathPositions[i] += (new Vector2Int(-minX, -minY) + new Vector2Int(padding, padding));
            }

            dungeon.primaryPathPositions = mPrimaryPathPositions;

            return(dungeon);
        }
예제 #6
0
        public void EvaluateDungeon(RandomDungeon dungeon)
        {
            int[] orthogonalOffsets = new int[] { 0, 1, 1, 0, 0, -1, -1, 0 };

            for (int x = 0; x < dungeon.width; ++x)
            {
                for (int y = 0; y < dungeon.height; ++y)
                {
                    // Only evaluate walkable tiles
                    if (dungeon.TileType(x, y) != RandomDungeonTileData.WALKABLE_TILE && dungeon.TileType(x, y) != RandomDungeonTileData.EXIT_TILE)
                    {
                        continue;
                    }

                    RandomDungeonTileData data = dungeon.Data(x, y);

                    // If the room isn't already part of the set, add it
                    RandomDungeonNetworkNode node = null;
                    if (!mNodeMap.TryGetValue(data.room, out node))
                    {
                        node        = new RandomDungeonNetworkNode();
                        node.roomId = data.room;
                        node.distanceFromPrimaryPath = data.distanceFromPrimaryPath;

                        mNodeMap.Add(data.room, node);
                    }

                    // Distance from primary path should be the closest tile that we can get into for this room.
                    node.distanceFromPrimaryPath = Mathf.Min(data.distanceFromPrimaryPath, node.distanceFromPrimaryPath);

                    // Evaluate connections (orthogonally, only considering walkable / exit tiles)
                    for (int i = 0; i < orthogonalOffsets.Length; i += 2)
                    {
                        int neighborX = x + orthogonalOffsets[i];
                        int neighborY = y + orthogonalOffsets[i + 1];

                        if (dungeon.IsPositionInBounds(neighborX, neighborY))
                        {
                            RandomDungeonTileData neighborData = dungeon.Data(neighborX, neighborY);
                            bool isWalkable = (neighborData.tileType == RandomDungeonTileData.WALKABLE_TILE || neighborData.tileType == RandomDungeonTileData.EXIT_TILE);

                            if (isWalkable && neighborData.room != node.roomId && !node.ConnectionExists(neighborData.room))
                            {
                                node.AddConnection(neighborData.room);
                            }
                        }
                    }

                    // Keep track of all walkable tiles in this room so we know where we can spawn stuff.
                    // todo bdsowers - change the name of this
                    // By design it only keeps track of tiles that aren't next to a wall, but that
                    // isn't conveyed in the name.
                    // todo bdsowers - move a 'num surrounding walls' into map generation, as that can
                    // be useful for more than just this.
                    bool hasUnwalkableNeighbor = false;
                    for (int offsetX = -1; offsetX <= 1; ++offsetX)
                    {
                        for (int offsetY = -1; offsetY <= 1; ++offsetY)
                        {
                            int testX = x + offsetX;
                            int testY = y + offsetY;
                            if (!dungeon.IsPositionInBounds(testX, testY))
                            {
                                hasUnwalkableNeighbor = true;
                                continue;
                            }

                            char tileType = dungeon.TileType(testX, testY);
                            if (tileType != RandomDungeonTileData.WALKABLE_TILE &&
                                tileType != RandomDungeonTileData.EXIT_TILE)
                            {
                                hasUnwalkableNeighbor = true;
                                continue;
                            }
                        }
                    }

                    if (!hasUnwalkableNeighbor)
                    {
                        node.RegisterEmptyPosition(x, y);
                    }
                }
            }
        }