첫번째 던전 생성 코드 및 복도 막히지 않게 구현
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.Mathematics;
using UnityEngine;
public class CorridorFirstDungeonGenerator : SimpleRandomWalkDungeonGenerator
{
[SerializeField]
private int corridorLength = 14, corridorCount = 5;
[SerializeField]
private float roomPercent = 0.8f;
protected override void RunProceduralGeneration()
{
CorridorFirstGeneration();
}
private void CorridorFirstGeneration()
{
HashSet<Vector2Int> floorPositions = new HashSet<Vector2Int>();
HashSet<Vector2Int> potentialRoomPositions = new HashSet<Vector2Int>();
CreateCorridors(floorPositions, potentialRoomPositions);
HashSet<Vector2Int> roomPositions = CreateRooms(potentialRoomPositions);
List<Vector2Int> deadEnds = FindAllDeadEnds(floorPositions);
CreatRoomsAtDeadEnd(deadEnds, roomPositions);
floorPositions.UnionWith(roomPositions);
tilemapVisualizer.PaintFloorTiles(floorPositions);
WallGenerator.CreateWalls(floorPositions, tilemapVisualizer);
}
private void CreatRoomsAtDeadEnd(List<Vector2Int> deadEnds, HashSet<Vector2Int> roomFloors)
{
foreach (var position in deadEnds)
{
if(roomFloors.Contains(position) == false)
{
var room = RunRandomWalk(randomWalkParameters, position);
roomFloors.UnionWith(room);
}
}
}
private List<Vector2Int> FindAllDeadEnds(HashSet<Vector2Int> floorPositions)
{
List<Vector2Int> deadEnds = new List<Vector2Int>();
foreach (var position in floorPositions)
{
int neighboursCount = 0;
foreach (var direction in Direction2D.cardinalDirectionsList)
{
if (floorPositions.Contains(position + direction))
neighboursCount++;
}
if (neighboursCount == 1)
deadEnds.Add(position);
}
return deadEnds;
}
private HashSet<Vector2Int> CreateRooms(HashSet<Vector2Int> potentialRoomPositions)
{
HashSet<Vector2Int> roomPositions = new HashSet<Vector2Int>();
int roomToCreateCount = Mathf.RoundToInt(potentialRoomPositions.Count * roomPercent);
List<Vector2Int> roomToCreate = potentialRoomPositions.OrderBy(bool2x2 => Guid.NewGuid()).Take(roomToCreateCount).ToList();
foreach (var roomPosition in roomToCreate)
{
var roomFloor = RunRandomWalk(randomWalkParameters, roomPosition);
roomPositions.UnionWith(roomFloor);
}
return roomPositions;
}
private void CreateCorridors(HashSet<Vector2Int> floorPositions, HashSet<Vector2Int> potentialRoomPositions)
{
var currentPosition = startPosition;
potentialRoomPositions.Add(currentPosition);
for (int i = 0; i < corridorCount; i++)
{
var corridor = ProceduralGenerationAlgorithms.RandomWalkCorridor(currentPosition, corridorLength);
currentPosition = corridor[corridor.Count - 1];
potentialRoomPositions.Add(currentPosition);
floorPositions.UnionWith(corridor);
}
}
}
수정
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Random = UnityEngine.Random;
public class SimpleRandomWalkDungeonGenerator : AbstractDungeonGenerator
{
[SerializeField]
protected SimpleRandomWalkSO randomWalkParameters;
protected override void RunProceduralGeneration()
{
HashSet<Vector2Int> floorPositions = RunRandomWalk(randomWalkParameters, startPosition);
tilemapVisualizer.Clear();
tilemapVisualizer.PaintFloorTiles(floorPositions);
WallGenerator.CreateWalls(floorPositions, tilemapVisualizer);
}
protected HashSet<Vector2Int> RunRandomWalk(SimpleRandomWalkSO parameters, Vector2Int position)
{
var currentPosition = position;
HashSet<Vector2Int> floorPositions = new HashSet<Vector2Int>();
for (int i = 0; i < parameters.iterations; i++)
{
var path = ProceduralGenerationAlgorithms.SimpleRandomWalk(currentPosition, parameters.walkLenght);
floorPositions.UnionWith(path);
if (parameters.startRandomlyEachIteration)
currentPosition = floorPositions.ElementAt(Random.Range(0, floorPositions.Count));
}
return floorPositions;
}
}
던전 맵
생성기
이진 공간 분할 알고리즘 시작
추가 코드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class ProceduralGenerationAlgorithms
{
public static HashSet<Vector2Int> SimpleRandomWalk(Vector2Int startPosition, int walkLenght)
{
HashSet<Vector2Int> path = new HashSet<Vector2Int>();
path.Add(startPosition); //시작
var previousPosition = startPosition;
for (int i = 0; i < walkLenght; i++)
{
var newPosition = previousPosition + Direction2D.GetRandomCardinalDirection();
path.Add(newPosition);
previousPosition = newPosition;
}
return path;
}
public static List<Vector2Int> RandomWalkCorridor(Vector2Int startPosition, int corriderLength)
{
List<Vector2Int> corridor = new List<Vector2Int>();
var direction = Direction2D.GetRandomCardinalDirection();
var currentPosition = startPosition;
corridor.Add(currentPosition);
for (int i = 0; i < corriderLength; i++)
{
currentPosition += direction;
corridor.Add(currentPosition);
}
return corridor;
}
public static List<BoundsInt> BinarySpacePartitioning(BoundsInt spaceToSplit, int minwidth, int minHeight)
{
Queue<BoundsInt> roomsQueue = new Queue<BoundsInt>();
List<BoundsInt> roomList = new List<BoundsInt>();
roomsQueue.Enqueue(spaceToSplit);
while(roomsQueue.Count > 0)
{
var room = roomsQueue.Dequeue();
if(room.size.y >= minHeight && room.size.x >= minwidth)
{
if (UnityEngine.Random.value < 0.5f)
{
if(room.size.y >= minHeight * 2)
{
SplitHorizontally(minwidth, minHeight, roomsQueue, room);
}else if(room.size.x >= minwidth * 2)
{
SplitVertically(minwidth, minHeight, roomsQueue, room);
}else if(room.size.x >= minwidth && room.size.y >= minHeight)
{
roomList.Add(room);
}
}
else
{
if (room.size.x >= minwidth * 2)
{
SplitVertically(minwidth, minHeight, roomsQueue, room);
}
else if (room.size.y >= minHeight * 2)
{
SplitHorizontally(minwidth, minHeight, roomsQueue, room);
}
else if (room.size.x >= minwidth && room.size.y >= minHeight)
{
roomList.Add(room);
}
}
}
}
return roomList;
}
private static void SplitVertically(int minwidth, int minHeight, Queue<BoundsInt> roomsQueue, BoundsInt room)
{
throw new System.NotImplementedException();
}
private static void SplitHorizontally(int minwidth, int minHeight, Queue<BoundsInt> roomsQueue, BoundsInt room)
{
throw new System.NotImplementedException();
}
}
public static class Direction2D
{
public static List<Vector2Int> cardinalDirectionsList = new List<Vector2Int>
{
new Vector2Int(0,1), //위
new Vector2Int(1,0), //오른쪽
new Vector2Int(0, -1), //아래
new Vector2Int(-1, 0) //왼쪽
};
public static Vector2Int GetRandomCardinalDirection()
{
return cardinalDirectionsList[Random.Range(0, cardinalDirectionsList.Count)];
}
}
이해가 잘 안간다..;; 어렵다
수직분할과 수평분할 얘기같다..
코드 추가
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class ProceduralGenerationAlgorithms
{
public static HashSet<Vector2Int> SimpleRandomWalk(Vector2Int startPosition, int walkLenght)
{
HashSet<Vector2Int> path = new HashSet<Vector2Int>();
path.Add(startPosition); //시작
var previousPosition = startPosition;
for (int i = 0; i < walkLenght; i++)
{
var newPosition = previousPosition + Direction2D.GetRandomCardinalDirection();
path.Add(newPosition);
previousPosition = newPosition;
}
return path;
}
public static List<Vector2Int> RandomWalkCorridor(Vector2Int startPosition, int corriderLength)
{
List<Vector2Int> corridor = new List<Vector2Int>();
var direction = Direction2D.GetRandomCardinalDirection();
var currentPosition = startPosition;
corridor.Add(currentPosition);
for (int i = 0; i < corriderLength; i++)
{
currentPosition += direction;
corridor.Add(currentPosition);
}
return corridor;
}
public static List<BoundsInt> BinarySpacePartitioning(BoundsInt spaceToSplit, int minwidth, int minHeight)
{
Queue<BoundsInt> roomsQueue = new Queue<BoundsInt>();
List<BoundsInt> roomList = new List<BoundsInt>();
roomsQueue.Enqueue(spaceToSplit);
while(roomsQueue.Count > 0)
{
var room = roomsQueue.Dequeue();
if(room.size.y >= minHeight && room.size.x >= minwidth)
{
if (UnityEngine.Random.value < 0.5f)
{
if(room.size.y >= minHeight * 2)
{
SplitHorizontally(minHeight, roomsQueue, room);
}else if(room.size.x >= minwidth * 2)
{
SplitVertically(minwidth, roomsQueue, room);
}else if(room.size.x >= minwidth && room.size.y >= minHeight)
{
roomList.Add(room);
}
}
else
{
if (room.size.x >= minwidth * 2)
{
SplitVertically(minwidth, roomsQueue, room);
}
else if (room.size.y >= minHeight * 2)
{
SplitHorizontally(minHeight, roomsQueue, room);
}
else if (room.size.x >= minwidth && room.size.y >= minHeight)
{
roomList.Add(room);
}
}
}
}
return roomList;
}
private static void SplitVertically(int minwidth, Queue<BoundsInt> roomsQueue, BoundsInt room)
{
var xSplit = Random.Range(1, room.size.x);
BoundsInt room1 = new BoundsInt(room.min, new Vector3Int(xSplit, room.min.y, room.min.z));
BoundsInt room2 = new BoundsInt(new Vector3Int(room.min.x + xSplit, room.min.y, room.min.z),
new Vector3Int(room.size.x - xSplit, room.size.y, room.size.z));
roomsQueue.Enqueue(room1);
roomsQueue.Enqueue(room2);
}
private static void SplitHorizontally(int minHeight, Queue<BoundsInt> roomsQueue, BoundsInt room)
{
var ySplit = Random.Range(1, room.size.y); //최소높이 = y - 높이
BoundsInt room1 = new BoundsInt(room.min, new Vector3Int(room.size.x, ySplit, room.min.z));
BoundsInt room2 = new BoundsInt(new Vector3Int(room.min.x, room.min.y + ySplit, room.min.z),
new Vector3Int(room.size.x, room.size.y - ySplit, room.size.z));
roomsQueue.Enqueue(room1);
roomsQueue.Enqueue(room2);
}
}
public static class Direction2D
{
public static List<Vector2Int> cardinalDirectionsList = new List<Vector2Int>
{
new Vector2Int(0,1), //위
new Vector2Int(1,0), //오른쪽
new Vector2Int(0, -1), //아래
new Vector2Int(-1, 0) //왼쪽
};
public static Vector2Int GetRandomCardinalDirection()
{
return cardinalDirectionsList[Random.Range(0, cardinalDirectionsList.Count)];
}
}
'Project T > 진행' 카테고리의 다른 글
[팀 프로젝트] - 랜덤 워크와 이진 공간 분할 알고리즘(맵 생성 종료) (0) | 2021.12.03 |
---|---|
[팀 프로젝트] - 랜덤 워크와 이진 공간 분할 알고리즘(맵 생성6) (0) | 2021.12.03 |
[팀 프로젝트] - 랜덤 워크와 이진 공간 분할 알고리즘(맵 생성4) (0) | 2021.12.01 |
[팀 프로젝트] - 랜덤 워크와 이진 공간 분할 알고리즘(맵 생성3) (0) | 2021.11.30 |
[팀 프로젝트] - 랜덤 워크와 이진 공간 분할 알고리즘(맵 생성2) (0) | 2021.11.29 |