2024. 1. 9. 08:46ㆍ스파르타코딩클럽 게임개발
던전을 만드는 DungeonGenerator을 만들었다.
이 부분을 다루는 내용은 워낙 길어 추후에 정리해서 다시 올리도록 하는 편이 좋을것 같다.
하지만 여기서 사용한 알고리즘이 몇개 있는데 그 부분을 소개해 보도록 하겠다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
public static class ProveduralGenerationAlgorithms
{
public static List<Vector2Int> PositionPoints = new List<Vector2Int>();
public static HashSet<Vector2Int> SimpleRandomWalk(Vector2Int startPosition, int walkLength)
{
HashSet<Vector2Int> path = new HashSet<Vector2Int>();
path.Add(startPosition);
var previousPosition = startPosition;
for (int i = 0; i < walkLength; i++)
{
var newPosition = previousPosition + Direction2D.GetRandomCardinalDirection();
path.Add(newPosition);
previousPosition = newPosition;
}
return path;
}
public static List<Vector2Int> RandomWalkCorridor(Vector2Int startPosition, int corridorLength)
{
List<Vector2Int> corridor = new List<Vector2Int>();
var direction = Direction2D.GetRandomCardinalDirection();
var currentPosition = startPosition;
corridor.Add(currentPosition);
for (int i = 0; i < corridorLength; i++)
{
currentPosition += direction;
corridor.Add(currentPosition);
}
return corridor;
}
public static List<BoundsInt> BinarySpacePartitioning(BoundsInt spaceToSprit, int minWidth, int minHeigth)
{
Queue<BoundsInt> roomsQueue = new Queue<BoundsInt>();
List<BoundsInt> roomsList = new List<BoundsInt>();
roomsQueue.Enqueue(spaceToSprit);
while (roomsQueue.Count > 0)
{
var room = roomsQueue.Dequeue();
if (room.size.y >= minHeigth && room.size.x >= minWidth)
{
if (Random.value < 0.5f)
{
if (room.size.y >= minHeigth * 2)
{
SplitHorizontally(minHeigth, roomsQueue, room);
}
else if (room.size.x >= minWidth * 2)
{
SpiltVertically(minWidth, roomsQueue, room);
}
else if (room.size.x >= minWidth && room.size.y >= minHeigth)
{
roomsList.Add(room);
}
}
else
{
if (room.size.x >= minWidth * 2)
{
SpiltVertically(minWidth, roomsQueue, room);
}
else if (room.size.y >= minHeigth * 2)
{
SplitHorizontally(minHeigth, roomsQueue, room);
}
else if (room.size.x >= minWidth && room.size.y >= minHeigth)
{
roomsList.Add(room);
}
}
}
}
return roomsList;
}
private static void SpiltVertically(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.size.y, room.size.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 minHeigth, Queue<BoundsInt> roomsQueue, BoundsInt room)
{
var ySplit = Random.Range(1, room.size.y);
BoundsInt room1 = new BoundsInt(room.min, new Vector3Int(room.size.x, ySplit, room.size.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), // UP
new Vector2Int(1,0), // RIGHT
new Vector2Int(0,-1), // DOWN
new Vector2Int(-1,0), // LEFT
};
public static List<Vector2Int> diagonalDirectionsList = new List<Vector2Int>
{
new Vector2Int(1,1), // UP-RIGHT
new Vector2Int(1,-1), // RIGHT -DOWN
new Vector2Int(-1,-1), // DOWN - LEFT
new Vector2Int(-1,1), // LEFT - UP
};
public static List<Vector2Int> eightDirectionsList = new List<Vector2Int>
{
new Vector2Int(0,1), //UP
new Vector2Int(1,1), //UP-RIGHT
new Vector2Int(1,0), //RIGHT
new Vector2Int(1,-1), //RIGHT-DOWN
new Vector2Int(0, -1), // DOWN
new Vector2Int(-1, -1), // DOWN-LEFT
new Vector2Int(-1, 0), //LEFT
new Vector2Int(-1, 1) //LEFT-UP
};
public static Vector2Int GetRandomCardinalDirection()
{
return cardinalDirectionsList[Random.Range(0, cardinalDirectionsList.Count)];
}
}
1. 간단한 랜덤 워크 (Simple Random Walk)
목적: 시작 위치에서 랜덤한 경로를 생성한다.
작동 방식: 시작 위치에서 시작하여 지정된 길이만큼 반복하면서 매 단계마다 랜덤한 기본 방향(상, 하, 좌, 우)으로 이동한다.
활용: 미로 생성, 지형 생성 등에 사용될 수 있다.
2. 랜덤 워크 복도 (Random Walk Corridor)
목적: 시작 위치에서 일정한 방향으로 이동하면서 복도를 생성한다.
작동 방식: 먼저 랜덤한 방향을 결정하고, 그 방향으로 지정된 길이만큼 이동하면서 복도를 생성한다.
활용: 던전 또는 복도 형태의 지형 생성에 적합한다.
3. 이진 공간 분할 (Binary Space Partitioning)
목적: 주어진 공간을 분할하여 여러 개의 방이나 영역을 생성한다.
작동 방식:
주어진 공간을 수직 또는 수평으로 랜덤하게 분할한다.
분할된 각 공간이 최소 너비와 높이 조건을 만족하면 추가로 분할하거나 최종 방 목록에 추가한다.
이 과정을 모든 공간에 대해 반복한다.
활용: 복잡한 레이아웃의 던전이나 방 구조 생성에 사용된다.
4. 방향 관련 유틸리티 (Direction2D)
목적: 2D 게임에서 사용할 수 있는 다양한 방향을 제공한다.
제공 방향:
cardinalDirectionsList: 기본 방향 (상, 하, 좌, 우)
diagonalDirectionsList: 대각선 방향
eightDirectionsList: 기본 및 대각선 방향을 모두 포함하는 8방향
활용: 랜덤 워크 및 기타 알고리즘에서 방향 결정에 사용된다.
'스파르타코딩클럽 게임개발' 카테고리의 다른 글
오늘은 스파르타 코딩 클럽 unity 게임 개발 과정 49일차(팀 프로젝트 마무리) (0) | 2024.01.10 |
---|---|
오늘은 스파르타 코딩 클럽 unity 게임 개발 과정 48일차(간단한 사운드 매니저) (0) | 2024.01.09 |
오늘은 스파르타 코딩 클럽 unity 게임 개발 과정 46일차(인벤토리 시스템 3 크래프팅!) (2) | 2024.01.05 |
오늘은 스파르타 코딩 클럽 unity 게임 개발 과정 45일차(인벤토리 시스템 2) (0) | 2024.01.04 |
오늘은 스파르타 코딩 클럽 unity 게임 개발 과정 44일차(ResourceManager 클래스 사용하는법) (2) | 2024.01.03 |