예제 #1
0
        public static Level GenerateLevel(LevelData data, Random random)
        {
            Level level = new Level(data.size);

            #region Create Rooms
            int roomCount = random.Next(data.minRoomCount, data.maxRoomCount + 1);
            level.rooms = new List <Room>(roomCount);
            Vector2Int roomSize, roomPosition;

            for (int i = 0; i < roomCount; i++)
            {
                roomSize     = new Vector2Int(random.Next(data.minRoomSize, data.maxRoomSize), random.Next(data.minRoomSize, data.maxRoomSize));
                roomPosition = new Vector2Int(random.Next(0, data.size - roomSize.x), random.Next(0, data.size - roomSize.y));
                level.rooms.Add(new Room(roomPosition, roomSize));
            }

            Node roomNode;

            foreach (Room room in level.rooms)
            {
                for (int x = 0; x < room.size.x; x++)
                {
                    for (int y = 0; y < room.size.y; y++)
                    {
                        roomNode        = level.nodes[x + room.position.x, y + room.position.y];
                        roomNode.filled = true;
                        roomNode.locked = true;
                    }
                }
            }
            #endregion

            #region Create Paths
            Pathfinding <Node> pathfinding = new Pathfinding <Node>(data.size * data.size, level.nodes);
            List <Vector2Int>  path = new List <Vector2Int>(data.size * data.size);
            Room       startRoom, endRoom;
            Vector2Int from, to;
            int        connectionAmount, endRoomIndex;

            for (int i = 0; i < roomCount; i++)
            {
                startRoom        = level.rooms[i];
                connectionAmount = random.Next(1, 2 + data.maxExtraPathsPerRoom);

                for (int j = 0; j < connectionAmount; j++)
                {
                    endRoomIndex = random.Next(0, roomCount);
                    if (level.rooms[endRoomIndex] == startRoom)
                    {
                        endRoomIndex++;
                    }
                    endRoom = level.rooms[endRoomIndex];

                    from = new Vector2Int(random.Next(0, startRoom.size.x) + startRoom.position.x, random.Next(0, startRoom.size.y) + startRoom.position.y);
                    to   = new Vector2Int(random.Next(0, endRoom.size.x) + endRoom.position.x, random.Next(0, endRoom.size.y) + endRoom.position.y);

                    pathfinding.Calculate2D(path, from, to, false);

                    foreach (Vector2Int vec in path)
                    {
                        roomNode        = level.nodes[vec.x, vec.y];
                        roomNode.filled = true;
                        roomNode.locked = true;
                    }
                    path.Clear();
                }
            }
            #endregion

            #region Cellular Automata
            Node levelNode;

            Func <int, int, bool, bool> isCorrespondingNeighbour = delegate(int x, int y, bool filled)
            {
                if (level.IsOutOfBounds(x, y))
                {
                    return(true);
                }

                return(level.nodes[x, y].filled == filled);
            };

            for (int x = 0; x < data.size; x++)
            {
                for (int y = 0; y < data.size; y++)
                {
                    levelNode = level.nodes[x, y];

                    if (levelNode.locked)
                    {
                        continue;
                    }

                    levelNode.filled = random.NextDouble() < data.fillPercentage;
                }
            }

            int  neighbourCount;
            bool neighbourFilled;

            for (int i = 0; i < data.smoothAmount; i++)
            {
                for (int x = 0; x < data.size; x++)
                {
                    for (int y = 0; y < data.size; y++)
                    {
                        neighbourCount  = 0;
                        neighbourFilled = level.nodes[x, y].filled;

                        if (isCorrespondingNeighbour(x, y + 1, neighbourFilled))
                        {
                            neighbourCount++;
                        }
                        if (isCorrespondingNeighbour(x + 1, y, neighbourFilled))
                        {
                            neighbourCount++;
                        }
                        if (isCorrespondingNeighbour(x, y - 1, neighbourFilled))
                        {
                            neighbourCount++;
                        }
                        if (isCorrespondingNeighbour(x - 1, y, neighbourFilled))
                        {
                            neighbourCount++;
                        }

                        if (neighbourCount < 2)
                        {
                            level.nodes[x, y].filled = !level.nodes[x, y].filled;
                        }
                    }
                }
            }

            #endregion

            #region Ensure Connectivity
            Vector2Int levelRoot = level.rooms[0].position;

            foreach (Node node in level.nodes)
            {
                node.Walkable = node.filled;
            }

            for (int x = 0; x < data.size; x++)
            {
                for (int y = 0; y < data.size; y++)
                {
                    if (level.nodes[x, y].locked || !level.nodes[x, y].filled)
                    {
                        continue;
                    }

                    path.Clear();
                    from = new Vector2Int(x, y);
                    pathfinding.Calculate2D(path, from, levelRoot, false);

                    if (path.Count == 0)
                    {
                        pathfinding.CalculateFill2D(path, from, false);

                        foreach (Vector2Int vec in path)
                        {
                            levelNode = level.nodes[vec.x, vec.y];
                            if (levelNode.filled)
                            {
                                levelNode.filled = false;
                            }
                        }
                    }
                }
            }
            #endregion

            return(level);
        }