232 lines
No EOL
10 KiB
C#
232 lines
No EOL
10 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Unity.VisualScripting;
|
|
using UnityEngine;
|
|
using Random = System.Random;
|
|
|
|
namespace DungeonGenerator
|
|
{
|
|
public class DungeonGenerator
|
|
{
|
|
private const int SIDE_LENGTH_OF_MONSTER = 4;
|
|
private const int SIDE_LENGTH_OF_NORMAL = 2;
|
|
|
|
private List<Room> _monsterRooms = new List<Room>();
|
|
private int _xLength = 40;
|
|
private int _yLength = 28;
|
|
private List<Point> _entrancePoints;
|
|
|
|
public void GenerateDungeon(int length, float monsterRoomRatio)
|
|
{
|
|
_xLength = 40;
|
|
_yLength = 28;
|
|
|
|
Random random = new Random();
|
|
List<Room> entranceRooms = GenerateEntranceRooms(_xLength, _yLength, random.Next(1,4));
|
|
_entrancePoints = entranceRooms.SelectMany(room => room.GetPointsInRoom()).ToList();
|
|
|
|
EvenDisperser disperser = new EvenDisperser(_xLength, _yLength, _entrancePoints); //TODO calculate L and W from length
|
|
int numberOfMonsterRooms = 7; // TODO: Calculate from ratio
|
|
|
|
for (var i = 0; i < numberOfMonsterRooms; i ++)
|
|
{
|
|
_monsterRooms.Add(disperser.GenerateAndPlaceRoom(
|
|
SIDE_LENGTH_OF_MONSTER,
|
|
SIDE_LENGTH_OF_MONSTER,
|
|
RoomType.Monster));
|
|
}
|
|
}
|
|
|
|
public void PrintMap()
|
|
{
|
|
List<Point> monsterRoomPoints = _monsterRooms.SelectMany(room => room.GetPointsInRoom()).ToList();
|
|
char[,] mapMatrix = new Char[_xLength, _yLength];
|
|
for (int x = 0; x < _xLength; x++)
|
|
{
|
|
for (int y = 0; y < _yLength; y++)
|
|
{
|
|
if (_entrancePoints.Contains(new Point(x, y)))
|
|
{
|
|
mapMatrix[x, y] = '*';
|
|
}
|
|
else if (monsterRoomPoints.Contains(new Point(x,y)))
|
|
{
|
|
mapMatrix[x, y] = 'X';
|
|
}
|
|
else
|
|
{
|
|
mapMatrix[x, y] = '-';
|
|
}
|
|
}
|
|
}
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
for (int j = 0; j < mapMatrix.GetLength(1); j++)
|
|
{
|
|
for (int i = 0; i < mapMatrix.GetLength(0); i++)
|
|
{
|
|
sb.Append(mapMatrix[i, j] + " ");
|
|
}
|
|
sb.Append(Environment.NewLine);
|
|
}
|
|
|
|
Debug.Log($"{DateTime.Now}{Environment.NewLine}" +
|
|
$"X Length: {_xLength}{Environment.NewLine}" +
|
|
$"Y Length: {_yLength}{Environment.NewLine}" +
|
|
$"Monster Rooms: {_monsterRooms.Count}{Environment.NewLine}" +
|
|
sb.ToString());
|
|
}
|
|
|
|
private enum Side
|
|
{
|
|
Top,
|
|
Right,
|
|
Bottom,
|
|
Left
|
|
}
|
|
|
|
private List<Room> GenerateEntranceRooms(int xLengthOfDungeon, int yLengthOfDungeon, int numberOfEntranceLines)
|
|
{
|
|
if (numberOfEntranceLines > 4)
|
|
{
|
|
throw new Exception("Number of entrance lines cannot be greater than 4");
|
|
}
|
|
|
|
const int numEntranceRooms = 12;
|
|
List<Room> entranceRooms = new List<Room>();
|
|
Random random = new Random();
|
|
Dictionary<Side, int> sidesToEnterOn = new()
|
|
{
|
|
{ Side.Top, 0},
|
|
{ Side.Right, 0},
|
|
{ Side.Bottom, 0},
|
|
{ Side.Left, 0}
|
|
};
|
|
|
|
// Randomly assign starting lines to sides of dungeon
|
|
for (var i = 0; i < numberOfEntranceLines; i++)
|
|
{
|
|
while (true)
|
|
{
|
|
Side side = (Side)random.Next(0, 4);
|
|
if (sidesToEnterOn[side] < 2)
|
|
{
|
|
sidesToEnterOn[side] += 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int roomsPerLine = numEntranceRooms / numberOfEntranceLines;
|
|
int bottom = yLengthOfDungeon - SIDE_LENGTH_OF_NORMAL;
|
|
int oneRoomFromBottom = bottom - SIDE_LENGTH_OF_NORMAL;
|
|
int right = xLengthOfDungeon - SIDE_LENGTH_OF_NORMAL;
|
|
// Generate entrance lines on each side
|
|
switch (sidesToEnterOn[Side.Top])
|
|
{
|
|
case 2:
|
|
// Add half of points for this entrance line to the top left side
|
|
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
|
|
{
|
|
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(i,0)));
|
|
}
|
|
|
|
// Add the rest of the points for this entrance line to the top right side.
|
|
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
|
|
{
|
|
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right - i,0)));
|
|
}
|
|
break;
|
|
case 1:
|
|
int startOfLine = GetStartOfCenteredLine(xLengthOfDungeon, roomsPerLine, SIDE_LENGTH_OF_NORMAL);
|
|
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
|
|
{
|
|
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL,new Point(startOfLine + i, 0)));
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch (sidesToEnterOn[Side.Right])
|
|
{
|
|
case 2:
|
|
// Add points for this entrance line to the top right side
|
|
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
|
|
{
|
|
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right, i + SIDE_LENGTH_OF_NORMAL)));
|
|
}
|
|
|
|
// Add the rest of the points for this entrance line to the bottom right side.
|
|
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
|
|
{
|
|
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right, oneRoomFromBottom - i)));
|
|
}
|
|
break;
|
|
case 1:
|
|
int startOfLine = GetStartOfCenteredLine(yLengthOfDungeon, roomsPerLine, SIDE_LENGTH_OF_NORMAL);
|
|
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
|
|
{
|
|
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right, startOfLine + i)));
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch (sidesToEnterOn[Side.Bottom])
|
|
{
|
|
case 2:
|
|
// Add half of points for this entrance line to the bottom left side
|
|
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
|
|
{
|
|
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(i, bottom)));
|
|
}
|
|
|
|
// Add the rest of the points for this entrance line to the bottom right side.
|
|
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
|
|
{
|
|
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point((xLengthOfDungeon - 1) - i, bottom)));
|
|
}
|
|
break;
|
|
case 1:
|
|
int startOfLine = GetStartOfCenteredLine(xLengthOfDungeon, roomsPerLine, SIDE_LENGTH_OF_NORMAL);
|
|
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
|
|
{
|
|
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(startOfLine + i, bottom)));
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch (sidesToEnterOn[Side.Left])
|
|
{
|
|
case 2:
|
|
// Add half of points for this entrance line to the top left side
|
|
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
|
|
{
|
|
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(0, i + SIDE_LENGTH_OF_NORMAL)));
|
|
}
|
|
|
|
// Add the rest of the points for this entrance line to the bottom left side.
|
|
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
|
|
{
|
|
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(0, oneRoomFromBottom - i)));
|
|
}
|
|
break;
|
|
case 1:
|
|
int startOfLine = GetStartOfCenteredLine(yLengthOfDungeon, roomsPerLine, SIDE_LENGTH_OF_NORMAL);
|
|
for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL)
|
|
{
|
|
entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(0, startOfLine + i)));
|
|
}
|
|
break;
|
|
}
|
|
|
|
return entranceRooms;
|
|
}
|
|
|
|
private int GetStartOfCenteredLine(int length, int numberOfRooms, int sizeOfRoom)
|
|
{
|
|
int midpoint = length / 2;
|
|
return midpoint - (numberOfRooms * sizeOfRoom / 2);
|
|
}
|
|
}
|
|
} |