이번 글에서는 통로를 완성시켜보겠다.
내가 몇번 살펴본 결과, 통로는
이렇게 2가지이다.
ㄷ자, ㄹ자는 등장하지 않는다. 따라서 일자와 위 사진 같은 경로만 만들면 된다.
그럼 어떻게할까? 간단하게 ㄱ자 2개를 만들기로 했다.
문과 문 사이에 지정된 범위 안에서 중간위치를 랜덤생성한 후, 시작점 - 중간위치, 중간위치 - 끝점 을 만들어주면 된다.
랜덤이 문앞에서 일어나면 부자연스러워지기 때문에 25%~75% 지점를 범위로 지정했다.
만약 각 x나 y의 값이 동일하다면 일자도 자연스레 만들어지기 때문에 이 방법을 택한다.
void GenerateCorridors(GameObject parent,Vector2 v, Vector2 v2, bool mode/* true : x -> y , false : y -> x */)
{
Debug.Log("mode : " + mode);
Vector2Int pos = new Vector2Int((int)v.x, (int)v.y);
Vector2Int pos2 = new Vector2Int((int)v2.x, (int)v2.y);
Debug.Log(pos.ToString());
Debug.Log(pos2.ToString());
if (mode)
{
// for문 수치 파악해보기
for (int x = pos.x; x != (pos2.x + ((pos2.x > pos.x) ? 1 : -1)); x += (pos2.x > pos.x) ? 1 : -1)
{
GameObject go = Instantiate(corridorTile, new Vector2(x, pos.y), Quaternion.identity);
go.transform.SetParent(parent.transform, true);
}
for (int y = pos.y; y != (pos2.y + ((pos2.y > pos.y) ? 1 : -1)); y += (pos2.y > pos.y) ? 1 : -1)
{
GameObject go = Instantiate(corridorTile, new Vector2(pos2.x, y), Quaternion.identity);
go.transform.SetParent(parent.transform, true);
}
}
else
{
for (int y = pos.y; y != (pos2.y + ((pos2.y > pos.y) ? 1 : -1)); y += (pos2.y > pos.y) ? 1 : -1)
{
GameObject go = Instantiate(corridorTile, new Vector2(pos.x, y), Quaternion.identity);
go.transform.SetParent(parent.transform, true);
}
for (int x = pos.x; x != (pos2.x + ((pos2.x > pos.x) ? 1 : -1)); x += (pos2.x > pos.x) ? 1 : -1)
{
GameObject go = Instantiate(corridorTile, new Vector2(x, pos2.y), Quaternion.identity);
go.transform.SetParent(parent.transform, true);
}
}
}
이게 함수이다.
IEnumerator GenerateCorridor()
{
// kruscal 알고리즘 실행..
foreach (Edge e in mst)
{
Vector2 randPos = GetRandomPos(door.transform.position, door2.transform.position);
bool mode;
Vector2 inputVec = door.transform.position;
Vector2 inputVec2 = door2.transform.position;
if (snappedDir == Vector2.up || snappedDir == Vector2.down)
{
mode = false;
if(snappedDir == Vector2.up)
{
inputVec.y++; inputVec2.y--;
}
else
{
inputVec2.y++; inputVec.y--;
}
}
else
{
mode = true;
if(snappedDir == Vector2.right)
{
inputVec2.x--;
}
else
{
inputVec.x--;
}
}
CreateCorridors(corridors, inputVec, randPos, mode);
CreateCorridors(corridors, randPos, inputVec2, !mode);
}
}
여기서 각 edge 마다 통로를 생성해준다. GetRandomPos를 통해서 중간지점 랜덤값을 받아온다.
그 값을 CreateCorridors 함수에 넘겨줘서 ㄱ자 통로를 생성하는 것이다.
if-else 문은 내가 한 프로젝트 특성상 다듬는 작업에 불과하다. 봐야할 것은 mode 뿐이다.
CreateCorridors함수는 mode변수로 true일때는 x-> y 순으로 ㄱ 같은 통로를 만들고, false 일때는 y->x 순으로 ㄴ 같은 모양을 만든다.
Vector2 GetRandomPos(Vector3 pos, Vector3 pos2)
{
float maxY = Mathf.Max(pos.y, pos2.y);
float minY = Mathf.Min(pos.y, pos2.y);
float maxX = Mathf.Max(pos.x, pos2.x);
float minX = Mathf.Min(pos.x, pos2.x);
int offsetY = Mathf.RoundToInt((maxY - minY) / 4);
int offsetX = Mathf.RoundToInt((maxX - minX) / 4);
float randX = Random.Range(minX + offsetX, maxX - offsetX);
float randY = Random.Range(minY + offsetY, maxY - offsetY);
randX = Mathf.Round(randX);
randY = Mathf.Round(randY);
Debug.Log("RandPoint : "+randX +", "+randY);
return new Vector2(randX, randY);
}
x, y 모두 25% ~ 75% 사이 랜덤값을 생성한다.
if (mode)
{
// for문 수치 파악해보기
for (int x = pos.x; x != (pos2.x + ((pos2.x > pos.x) ? 1 : -1)); x += (pos2.x > pos.x) ? 1 : -1)
{
GameObject go = Instantiate(corridorTile, new Vector2(x, pos.y), Quaternion.identity);
go.transform.SetParent(parent.transform, true);
}
for (int y = pos.y; y != (pos2.y + ((pos2.y > pos.y) ? 1 : -1)); y += (pos2.y > pos.y) ? 1 : -1)
{
GameObject go = Instantiate(corridorTile, new Vector2(pos2.x, y), Quaternion.identity);
go.transform.SetParent(parent.transform, true);
}
}
else
{
for (int y = pos.y; y != (pos2.y + ((pos2.y > pos.y) ? 1 : -1)); y += (pos2.y > pos.y) ? 1 : -1)
{
GameObject go = Instantiate(corridorTile, new Vector2(pos.x, y), Quaternion.identity);
go.transform.SetParent(parent.transform, true);
}
for (int x = pos.x; x != (pos2.x + ((pos2.x > pos.x) ? 1 : -1)); x += (pos2.x > pos.x) ? 1 : -1)
{
GameObject go = Instantiate(corridorTile, new Vector2(x, pos2.y), Quaternion.identity);
go.transform.SetParent(parent.transform, true);
}
}
CreateCorridors 의 로직을 살펴보겠다. mode에 따라서 for문 순서만 바뀐다.
위치에 따라서 생성해주는 코드인데, for문에 일일이 비교해서 pos.x 가 큰지 pos2.x 가 큰지 다 변수에 저장하고 비교하는 것은 코드가 더러워질것 같아서 ai에 물어보니 이런 우아한 코드를 알려줬다.
for (int x = pos.x; x != (pos2.x + ((pos2.x > pos.x) ? 1 : -1)); x += (pos2.x > pos.x) ? 1 : -1)
pos.x 로 시작한다. x가 pos2.x 보다 한칸 더 나아간 상태인지를 체크한다. (pos2.x 일때까지 실해하기 위함이다.)
x의 증가값을 삼항연산자로 정한다.
만약 pos2.x가 더 오른쪽에 있다면 1이 아니라면 -1이 자동으로 연산된다.
이로써 맵자동생성은 거의거의 완료되었다고 볼 수 있다.
남은 것은 방을 생성하는 코드 쪽에 추가해서 방안의 장애물, 구조물 등을 어떻게 추가할지만 생각하면 된다.
보면 방끼리 연결이 아주 잘 되어있다.
구조물 생성, 장애물 생성까지 다뤄서 맵 자동 생성을 마무리해보겠다.
'2d 자동 맵생성' 카테고리의 다른 글
맵 자동 생성(7) (0) | 2025.05.13 |
---|---|
맵 자동 생성(6) (0) | 2025.05.12 |
맵 자동 생성(4) (0) | 2025.05.11 |
맵 자동 생성(3) (0) | 2025.05.10 |
맵 자동 생성(2) (1) | 2025.05.09 |