Implemented randomly dispersing monster rooms.
This commit is contained in:
parent
5895a9f878
commit
9c02b11299
12 changed files with 394 additions and 0 deletions
|
|
@ -656,6 +656,7 @@ GameObject:
|
||||||
m_Component:
|
m_Component:
|
||||||
- component: {fileID: 126339302}
|
- component: {fileID: 126339302}
|
||||||
- component: {fileID: 126339304}
|
- component: {fileID: 126339304}
|
||||||
|
- component: {fileID: 126339305}
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: GameManager
|
m_Name: GameManager
|
||||||
m_TagString: Untagged
|
m_TagString: Untagged
|
||||||
|
|
@ -694,6 +695,18 @@ MonoBehaviour:
|
||||||
diceRoller: {fileID: 150116548}
|
diceRoller: {fileID: 150116548}
|
||||||
passManager: {fileID: 895359724}
|
passManager: {fileID: 895359724}
|
||||||
player: {fileID: 1476127625}
|
player: {fileID: 1476127625}
|
||||||
|
--- !u!114 &126339305
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 126339301}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 05a951debbad424aada4449064592d39, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
--- !u!1 &150116543
|
--- !u!1 &150116543
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
|
||||||
3
PuzzleGameProject/Assets/Scripts/DungeonGenerator.meta
Normal file
3
PuzzleGameProject/Assets/Scripts/DungeonGenerator.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b2976da120e9418ab6437c973c915dd7
|
||||||
|
timeCreated: 1738336012
|
||||||
|
|
@ -0,0 +1,218 @@
|
||||||
|
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;
|
||||||
|
|
||||||
|
public void GenerateDungeon(int length, float monsterRoomRatio)
|
||||||
|
{
|
||||||
|
_xLength = 40;
|
||||||
|
_yLength = 28;
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
List<Point> entrancePoints = GenerateEntrancePoints(_xLength, _yLength, random.Next(1,4));
|
||||||
|
|
||||||
|
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 ++)
|
||||||
|
{
|
||||||
|
Point newSpot = disperser.GetPoint(SIDE_LENGTH_OF_MONSTER, SIDE_LENGTH_OF_MONSTER);
|
||||||
|
_monsterRooms.Add(new Room(
|
||||||
|
RoomType.Monster,
|
||||||
|
SIDE_LENGTH_OF_MONSTER,
|
||||||
|
SIDE_LENGTH_OF_MONSTER,
|
||||||
|
newSpot));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PrintMap()
|
||||||
|
{
|
||||||
|
char[,] mapMatrix = new Char[_xLength, _yLength];
|
||||||
|
for (int x = 0; x < _xLength; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < _yLength; y++)
|
||||||
|
{
|
||||||
|
if (_monsterRooms.Any(room => room.PositionOfTopLeft.Equals(new Point(x,y))))
|
||||||
|
{
|
||||||
|
mapMatrix[x, y] = 'X';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mapMatrix[x, y] = 'O';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(sb.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum Side
|
||||||
|
{
|
||||||
|
Top,
|
||||||
|
Right,
|
||||||
|
Bottom,
|
||||||
|
Left
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Point> GenerateEntrancePoints(int xLengthOfDungeon, int yLengthOfDungeon, int numberOfEntranceLines)
|
||||||
|
{
|
||||||
|
if (numberOfEntranceLines > 4)
|
||||||
|
{
|
||||||
|
throw new Exception("Number of entrance lines cannot be greater than 4");
|
||||||
|
}
|
||||||
|
|
||||||
|
const int entranceSpaces = 12;
|
||||||
|
List<Point> entrancePoints = new List<Point>();
|
||||||
|
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 pointsPerLine = entranceSpaces / numberOfEntranceLines;
|
||||||
|
// 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 < pointsPerLine; i++)
|
||||||
|
{
|
||||||
|
entrancePoints.Add(new Point(i,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the rest of the points for this entrance line to the top right side.
|
||||||
|
int pointsRemaining = pointsPerLine;
|
||||||
|
for (var i = 0; i < pointsRemaining; i++)
|
||||||
|
{
|
||||||
|
entrancePoints.Add(new Point((xLengthOfDungeon - 1) - i,0));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
int midpoint = xLengthOfDungeon / 2;
|
||||||
|
int startOfLine = midpoint - (pointsPerLine / 2);
|
||||||
|
for (var i = 0; i < pointsPerLine; i++)
|
||||||
|
{
|
||||||
|
entrancePoints.Add(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 < pointsPerLine; i++)
|
||||||
|
{
|
||||||
|
entrancePoints.Add(new Point(xLengthOfDungeon - 1, i + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the rest of the points for this entrance line to the bottom right side.
|
||||||
|
for (var i = 0; i < pointsPerLine; i++)
|
||||||
|
{
|
||||||
|
entrancePoints.Add(new Point(xLengthOfDungeon - 1, (yLengthOfDungeon - 1) - i));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
int midpoint = yLengthOfDungeon / 2;
|
||||||
|
int startOfLine = midpoint - (pointsPerLine / 2);
|
||||||
|
for (int i = 0; i < pointsPerLine; i++)
|
||||||
|
{
|
||||||
|
entrancePoints.Add(new Point(xLengthOfDungeon - 1, 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 < pointsPerLine; i++)
|
||||||
|
{
|
||||||
|
entrancePoints.Add(new Point(i, yLengthOfDungeon - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the rest of the points for this entrance line to the bottom right side.
|
||||||
|
for (var i = 0; i < pointsPerLine; i++)
|
||||||
|
{
|
||||||
|
entrancePoints.Add(new Point((xLengthOfDungeon - 1) - i, yLengthOfDungeon - 1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
int midpoint = xLengthOfDungeon / 2;
|
||||||
|
int startOfLine = midpoint - (pointsPerLine / 2);
|
||||||
|
for (var i = 0; i < pointsPerLine; i++)
|
||||||
|
{
|
||||||
|
entrancePoints.Add(new Point(startOfLine + i, yLengthOfDungeon - 1));
|
||||||
|
}
|
||||||
|
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 < pointsPerLine; i++)
|
||||||
|
{
|
||||||
|
entrancePoints.Add(new Point(0, i + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the rest of the points for this entrance line to the bottom left side.
|
||||||
|
for (var i = 0; i < pointsPerLine; i++)
|
||||||
|
{
|
||||||
|
entrancePoints.Add(new Point(0, (yLengthOfDungeon - 1) - i));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
int midpoint = yLengthOfDungeon / 2;
|
||||||
|
int startOfLine = midpoint - (pointsPerLine / 2);
|
||||||
|
for (int i = 0; i < pointsPerLine; i++)
|
||||||
|
{
|
||||||
|
entrancePoints.Add(new Point(0, startOfLine + i));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entrancePoints;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e9db8a8571ad45d9a8d7c8d22ebe0d05
|
||||||
|
timeCreated: 1738336090
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
using Random = System.Random;
|
||||||
|
|
||||||
|
namespace DungeonGenerator
|
||||||
|
{
|
||||||
|
public class EvenDisperser
|
||||||
|
{
|
||||||
|
private List<Point> _samples = new List<Point>(){new Point(1,1)};
|
||||||
|
private List<Point> _availablePoints;
|
||||||
|
|
||||||
|
public EvenDisperser(int xLength, int yLength, List<Point> excludedPoints = null)
|
||||||
|
{
|
||||||
|
_availablePoints = GenerateAvailablePoints(xLength, yLength, excludedPoints ?? new List<Point>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Point> GenerateAvailablePoints(int xLength, int yLength, List<Point> excludedPoints)
|
||||||
|
{
|
||||||
|
List<Point> availablePoints = new List<Point>();
|
||||||
|
for (var x = 0; x < xLength; x++)
|
||||||
|
{
|
||||||
|
for (var y = 0; y < yLength; y++)
|
||||||
|
{
|
||||||
|
if (!excludedPoints.Contains(new Point(x, y)))
|
||||||
|
{
|
||||||
|
availablePoints.Add(new Point(x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return availablePoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can place point so that the x lengt hand y length go out of bounds to the right and down.
|
||||||
|
public Point GetPoint(int xLength, int yLength)
|
||||||
|
{
|
||||||
|
int numCandidates = 50; // Increasing improves results but greatly effects performance.
|
||||||
|
Random rnd = new Random();
|
||||||
|
int randomIndex = rnd.Next(_availablePoints.Count);
|
||||||
|
Point bestCandidate = new Point(Int32.MaxValue, Int32.MaxValue);
|
||||||
|
int bestDistance = 0;
|
||||||
|
for (var i = 0; i < numCandidates; i++)
|
||||||
|
{
|
||||||
|
var candidate = _availablePoints[randomIndex];
|
||||||
|
var distance = candidate.ManhattanDistance(FindClosest(_samples, candidate));
|
||||||
|
if (distance > bestDistance)
|
||||||
|
{
|
||||||
|
RemoveArea(candidate, xLength, yLength, _availablePoints);
|
||||||
|
bestCandidate = candidate;
|
||||||
|
bestDistance = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_samples.Add(bestCandidate);
|
||||||
|
return bestCandidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point FindClosest(List<Point> options, Point reference)
|
||||||
|
{
|
||||||
|
Point closest = options[0];
|
||||||
|
foreach (var option in options)
|
||||||
|
{
|
||||||
|
if (reference.ManhattanDistance(option) < reference.ManhattanDistance(closest))
|
||||||
|
{
|
||||||
|
closest = option;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveArea(Point topLeft, int xLength, int yLength, List<Point> availablePoints)
|
||||||
|
{
|
||||||
|
for (var x = topLeft.X; x < topLeft.X + xLength; x++)
|
||||||
|
{
|
||||||
|
for (var y = topLeft.Y; y < topLeft.Y + yLength; y++)
|
||||||
|
{
|
||||||
|
availablePoints.Remove(new Point(x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3ce67840c99f4761af7805355099b495
|
||||||
|
timeCreated: 1738577856
|
||||||
25
PuzzleGameProject/Assets/Scripts/DungeonGenerator/Point.cs
Normal file
25
PuzzleGameProject/Assets/Scripts/DungeonGenerator/Point.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DungeonGenerator
|
||||||
|
{
|
||||||
|
public struct Point
|
||||||
|
{
|
||||||
|
public int X { get; }
|
||||||
|
public int Y { get; }
|
||||||
|
|
||||||
|
public Point(int x, int y) {
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj) => obj is Point p && X == p.X && Y == p.Y;
|
||||||
|
public override int GetHashCode() => HashCode.Combine(X, Y);
|
||||||
|
|
||||||
|
public override string ToString() => $"({X}, {Y})";
|
||||||
|
|
||||||
|
public static Point operator +(Point a, Point b) => new Point(a.X + b.X, a.Y + b.Y);
|
||||||
|
public static Point operator -(Point a, Point b) => new Point(a.X - b.X, a.Y - b.Y);
|
||||||
|
|
||||||
|
public int ManhattanDistance(Point other) => Math.Abs(X - other.X) + Math.Abs(Y - other.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5c2b1ba54c4043b19dd204ab61f465c3
|
||||||
|
timeCreated: 1738579679
|
||||||
24
PuzzleGameProject/Assets/Scripts/DungeonGenerator/Room.cs
Normal file
24
PuzzleGameProject/Assets/Scripts/DungeonGenerator/Room.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
namespace DungeonGenerator
|
||||||
|
{
|
||||||
|
public enum RoomType
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
Monster,
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Room
|
||||||
|
{
|
||||||
|
public Room(RoomType roomType, int width, int height, Point positionOfTopLeft)
|
||||||
|
{
|
||||||
|
TypeOfRoom = roomType;
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
PositionOfTopLeft = positionOfTopLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoomType TypeOfRoom { get; set; }
|
||||||
|
public int Height { get; set; }
|
||||||
|
public int Width { get; set; }
|
||||||
|
public Point PositionOfTopLeft { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2dd79ebcc11d4938a8d116e711842b89
|
||||||
|
timeCreated: 1738337240
|
||||||
13
PuzzleGameProject/Assets/Scripts/DungeonGenerator/TestRun.cs
Normal file
13
PuzzleGameProject/Assets/Scripts/DungeonGenerator/TestRun.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class TestRun : MonoBehaviour
|
||||||
|
{
|
||||||
|
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
DungeonGenerator.DungeonGenerator gen = new DungeonGenerator.DungeonGenerator();
|
||||||
|
gen.GenerateDungeon(0 , 0.5f);
|
||||||
|
gen.PrintMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 05a951debbad424aada4449064592d39
|
||||||
Loading…
Add table
Add a link
Reference in a new issue