[C#, Unity, 절차적 생성] 절차적 던전 생성 - 2. 방 생성

2025. 5. 12. 18:52·Unity,C#/절차적생성(PCG)
728x90

■ 방 생성

[분할된 공간]

BSP 알고리즘을 통해 공갈이 분할되면, 자식이 없는 단말(리프) 노드에 실제 방을 생성해야 한다. 단말 노드들은 더 이상 분할되지 않는 영역이기 때문이다.

private List<RoomNode> GetAllLeafNode()
{
	var leafNodes = new List<RoomNode>();
	var queue = new Queue<RoomNode>(new[] { _roomNodeList[0] });
	
	while (queue.Count > 0)
	{
		var node = queue.Dequeue();
		
		if (node.ChildNode.Count <= 0)
		{
			leafNodes.Add(node);
			continue;
		}
		
		foreach (var chile in node.ChildNode)
		{
			queue.Enqueue((RoomNode)chile);
		}
	}
	
	return leafNodes;
}

 

너비 우선 탐색(BFS) 방식으로 트리를 순회하며, 자식 노드가 없는 경우(단말 노드)만 리스트에 추가한다.

 

■ 방 생성 구현

public class RoomGenerator
{
    private Vector2Int _offset;
    private float _minWeight;
    private float _maxWeight;

    public void GenerateRoom(List<RoomNode> leafNode, DungeonData data)
    {
        _offset = data.Offset;
        _minWeight = data.BottomLeftWeight;
        _maxWeight = data.TopRightWeight;

        foreach (var node in leafNode)
        {
            CreateRoomSpace(node);
        }
    }
}

방 생성을 위해 다음과 같이 RoomGenerator 클래스를 구현하였다.

  • BSP 이진트리에서 단말 노드만 저장한 리스트, 방 생성에 필요한 정보를 파라미터로 받는다.
  • 필요한 변수를 초기화 한 뒤, 단말 노드 안에 방을 생성한다.

 

1. 방의 좌하단(BL) 위치 구하기

private void CreateRoomSpace(RoomNode node)
{
		var curPos = node.Pos;
		
		// 최소, 최대 범위 계산
		var min = new Vector2Int(curPos.BL.x + _offset.x, curPos.BL.y + _offset.y);
		var max = new Vector2Int(curPos.TR.x - _offset.x, curPos.TR.y - _offset.y);
}

[위치 구하기]

노드 경계에서 일정 거리만큼 떨어진 좌표를 시작점으로 사용하여, 새롭게 생성되는 방이 기존 노드와 겹치지 않도록 만든다.


private void CreateRoomSpace(RoomNode node)
{
	// offset 계산 생략..
	
	// 방이 생성될 수 있는 길이 구하기
	var roomWidth = max.x - min.x;
	var roomHeight = max.y - min.y;
	
	var roomBL = new Vector2Int(
	Random.Range(min.x, min.x + (int)(roomWidth * _minWeight)),
	Random.Range(min.y, min.y + (int)(roomHeight * _minWeight)));
}

[좌하단 좌표 범위 구하기]
[좌하단 좌표 계산]

방이 생성될 수 있는 최대 범위는 min~max사이이다. 하지만 이 범위를 그대로 사용하면 우상단과 좌표가 겹칠 수 있으므로 일정 비율(Weight : 0.1~0.4)을 곱한 값을 최종 범위로 사용한다.

 

2. 방의 우상단(TR) 위치 구하기

// BL보다 무조건 커야함. 
var minTRX = roomBL.x + (int)(roomWidth * _maxWeight);
var minTRY = roomBL.y + (int)(roomHeight * _maxWeight);
        
var roomTR = new Vector2Int(
		Random.Range(minTRX, max.x),
		Random.Range(minTRY, max.y));
		
node.AddRoomPosition(new NodePosition(roomBL, roomTR));

[우상단 좌표 계산]

생성되는 방의 우상단 위치는 반드시 좌하단 좌표보다 커야 한다. 따라서 다음과 같이 우상단 좌표의 랜덤 범위를 구한다.

  • 최소 범위 : 좌하단 좌표 + 최대 크기 * Weight(0.6~0.9)
  • 최대 범위 : 기존 노드의 좌상단 좌표에서 -offset 만큼 이동한 좌표.

 

3. 방 위치 추가

public class RoomNode : BSP_Node
{
    public int Width => Mathf.Abs(Pos.BR.x - Pos.TL.x);
    public int Height => Mathf.Abs(Pos.TL.y - Pos.BL.y);
    public NodePosition RoomPosition { get; private set; }
        
    public RoomNode(BSP_Node parent, NodePosition position, int index) : base(parent)
    {
        Pos = position;
        Index = index;
        RoomPosition = null;
    }

    public void AddRoomPosition(NodePosition position)
    {
        RoomPosition = position;
    }
}

노드에 방 위치 정보를 저장하기 위해 RoomPosition변수를 추가한다.

  • NodePosition의 생성자는 좌상단, 우하단 좌표를 기준으로 나머지 좌표를 계산하므로 방의 좌표를 넘길 때도 동일하게 처리해주어야 한다.

 

■ 바닥 메시 생성

using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;

public class MeshGenerator : MonoBehaviour
{
    [Header("Component")] 
    [SerializeField] private Material[] floorMat;

    public void CreateMesh(NodePosition position)
    {
        var vertices = new Vector3[]
        {
            ConvertNodePositionToVector3(position.TL),
            ConvertNodePositionToVector3(position.TR),
            ConvertNodePositionToVector3(position.BL),
            ConvertNodePositionToVector3(position.BR)
        };

        var uvs = new Vector2[vertices.Length];
        for (var i = 0; i < uvs.Length; ++i)
        {
            uvs[i] = new Vector2(vertices[i].x, vertices[i].z);
        }

        var triangles = new int[]
        {
            0,1,2,2,1,3
        };

        var mesh = new Mesh
        {
            vertices = vertices,
            uv = uvs,
            triangles = triangles
        };

        var floor = new GameObject(position.BL + "Mesh", 
            typeof(MeshFilter), typeof(MeshRenderer));
        
        floor.transform.SetParent(transform);
        floor.GetComponent<MeshFilter>().mesh = mesh;
        floor.GetComponent<MeshRenderer>().material = floorMat[Random.Range(0, floorMat.Length)];
    }

    private Vector3 ConvertNodePositionToVector3(Vector2Int pos)
    {
        return new Vector3(pos.x, 0, pos.y);
    }
}

좌상단(TL), 우상단(TR), 좌하단(BL), 우하단(BR) 좌표를 기준으로 사각형 형태의 정점을 설정한다.

  • 각 정점의 x,z 좌표를 기준으로 UV좌표를 설정하여 텍스쳐가 매핑되도록 한다.

정점 0-1-2, 2-1-3을 기준으로 두 개의 삼각형을 구성한 뒤, 생성한 메쉬를 GameObject에 적용한다.

  • 바닥 머터리얼을 하나로 통일하고 싶다면, 마지막 floorMat[Random.Range(0, floorMat.Length)];를 수정하면 된다.

 

■ 결과

[최종 결과]

이렇게 분할된 공간 안에 방이 생성되고 방바닥이 위치한 결과를 확인할 수 있다. 다음에는 BSP알고리즘을 조금 개선해 보자.

728x90

'Unity,C# > 절차적생성(PCG)' 카테고리의 다른 글

[C#, Unity, 절차적 생성] 절차적 던전 생성 - 4. 복도 생성  (1) 2025.05.21
[C#, Unity, 절차적 생성] 절차적 던전 생성 - 3. BSP 알고리즘 개선  (1) 2025.05.12
[C#, Unity, 절차적 생성] 절차적 던전 생성 - 1. Binary Space Partitioning  (1) 2025.05.07
[C#, Unity, 절차적 생성] 절차적 지형 생성 - 3.터레인 생성  (0) 2025.04.28
[C#, Unity, 절차적 생성] 절차적 지형 생성 - 2.프랙탈 합  (2) 2025.04.24
'Unity,C#/절차적생성(PCG)' 카테고리의 다른 글
  • [C#, Unity, 절차적 생성] 절차적 던전 생성 - 4. 복도 생성
  • [C#, Unity, 절차적 생성] 절차적 던전 생성 - 3. BSP 알고리즘 개선
  • [C#, Unity, 절차적 생성] 절차적 던전 생성 - 1. Binary Space Partitioning
  • [C#, Unity, 절차적 생성] 절차적 지형 생성 - 3.터레인 생성
브라더스톤
브라더스톤
유티니, C#과 관련한 여러 정보를 끄적여둔 블로그입니다. Email : dkavmdk98@gmail.com
  • 브라더스톤
    젊은 프로그래머의 슬픔
    브라더스톤
  • 전체
    오늘
    어제
    • 개발 노트 (34) N
      • Unity,C# (27)
        • Unity 정보 (5)
        • 알고리즘 (11)
        • 자료구조 (2)
        • 절차적생성(PCG) (9)
      • 게임수학 (7) N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    절차적던전생성
    기저벡터
    C#
    이동변환
    최단경로찾기
    BSP
    게임수학
    pcg
    자료구조
    아핀공간
    경사로이동
    절차적지형생성
    앞뒤판별
    시야판별
    알고리즘
    ProjectOnPlane
    PerlinNoise
    정렬알고리즘
    이진공간분할
    unity
  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.3
브라더스톤
[C#, Unity, 절차적 생성] 절차적 던전 생성 - 2. 방 생성
상단으로

티스토리툴바