본문 바로가기
개발/Unity 내일배움캠프 TIL

Unity 3D 타일맵 만들기

by 석시 2023. 9. 25.



이번엔 3D로 타일맵을 만드는 법에 대해 다뤄보겠다.

보통 타일맵의 경우 2D 게임에서 많이 활용하지만 3D 게임의 경우도 활용할 수 있다.

3D에서 타일맵으로 레벨을 구성하면 마치 마인크래프트 같은 환경의 맵이 완성되는 것이다.


패키지 설치

먼저 3D 프로젝트를 생성하고 2D Tilemap Editor를 깔아주자.

[2D Tilemap Editor 설치] 상단 탭의 Window → Package Manager → 상단의 Packages: In Project를 Unity Registry로 변경 → 2D Tilemap Editor를 찾아서 설치

2D Tilemap이 맞는지 재차 물어볼 수 있겠다.

진짜 맞다!

같은 방법으로 2D Tilemap Extras 패키지까지 설치해주자.


타일맵 오브젝트 생성

Hierarchy에서 우클릭 → 2D Object → Tilemap → Rectangular

생성을 해보면 다음과 같이 우리가 의도한 바와는 다르게 타일맵이 바닥면에 깔린 것이 아니라 마치 벽이나 결계처럼 깔린 것을 볼 수 있다.

이를 바닥면에 위치하기 위해 타일맵을 생성할 때 같이 생성되는 Grid를 Inspector에서 수정해주자.

Grid의 Inspector에서 → Grid → Cell Swizzle을 XYZ에서 XZY로 설정

이제 그리드가 바닥면에 위치한 것을 확인할 수 있다.

추가로 Tilemap의 Inspector에서도 Tilemap 컴포넌트의 Orientation을 XY에서 XZ로 변경해주자.

지금 상태로 일반 타일맵처럼 사용할 수 있다.

하지만 타일을 칠할 수 있지만, 그렇게 채운 타일맵은 평면이다.

즉, 3D월드에서도 평면이라는 소리이다.

우리의 과제는 이러한 타일맵에 스프라이트를 배치하는 것이 아니라 3D 텍스쳐를 배치하는 것이다!


타일맵 브러쉬를 GameObject로 바꾸기

해당 기능은 2D Tilemap Extras 패키지를 설치해야 사용 가능함에 유의하자.

Tile Palette 창에서 Default Brush → GameObject

GameObject Brush의 필드를 살펴보자.

Inspector에서 Cells의 요소를 한 개 추가해보면 먼저 Brush로 그려서 배치할 프리팹 필드가 보인다.

그 외에 Grid의 한 칸 안의 위치를 결정해줄 Offset, 그리드 안에서 오브젝트의 크기인 Scale, 오브젝트의 방향인 Orientation이 있다.

Cells 밑에도 Size, Pivot, Anchor가 있는데 이것은 그려질 오브젝트의 Transform을 결정하는 것이 아니라 Brush의 특성을 결정한다.

Size를 증가하면 Cells의 크기가 증가하는데, 이렇게 하면 여러 종류의 오브젝트를 Brush를 한 번 적용해서 모두 배치할 수 있게 된다.

참고) 브러쉬 프리셋 저장하기

해당 브러쉬를 가지고 작업하다보면 다른 오브젝트를 브러쉬에 넣어 그릴 일이 있는데, 그러면 매 번 오브젝트를 브러쉬에 집어넣고 Offset, Scale 등의 값을 일일히 수정해줘야 한다.

이를 스크립트를 이용해 프리셋으로 저장하자.

스크립터블 오브젝트를 만들 때와 느낌이 매우 비슷하다.

PrefabBrush.cs라는 이름의 스크립트를 생성해 다음과 같이 작성해주자.

 
using UnityEditor.Tilemaps;
using UnityEngine;

[CreateAssetMenu(fileName = "Prefab brush", menuName = "Brushes/Prefab brush")]
[CustomGridBrush(false, true, false, "Prefab Brush")]
public class PrefabBrush : GameObjectBrush
{
    
}
 

이제 Create 메뉴로 들어가보면 Brushes → Prefab brush를 눌러 GameObject brush의 프리셋을 저장할 수 있게 된다.

여기까지 하면 브러쉬 프리셋으로 그리기까지는 되는데 그려놓은 오브젝트가 지워지지 않는다.

따라서 해당 문제를 해결하기 위해 기존 GameObjectBrushErase 메서드를 오버라이드 해줘야 한다.

public class PrefabBrush : GameObjectBrush
{
    public override void Erase(GridLayout gridLayout, GameObject brushTarget, Vector3Int position)
    {
        if (brushTarget.layer == 31)
        {
            return;
        }

        Transform erased =
            GetObjectInCell(gridLayout, brushTarget.transform, new Vector3Int(position.x, position.y, 0));
        if (erased != null)
            Undo.DestroyObjectImmediate(erased.gameObject);
    }

    private static Transform GetObjectInCell(GridLayout grid, Transform parent, Vector3Int position)
    {
        int childCount = parent.childCount;
        Vector3 min = grid.LocalToWorld(grid.CellToLocalInterpolated(position));
        Vector3 max = grid.LocalToWorld(grid.CellToLocalInterpolated(position + Vector3Int.one));
        Bounds bounds = new Bounds((max + min) * 0.5f, max - min);

        for (int i = 0; i < childCount; i++)
        {
            Transform child = parent.GetChild(i);
            if (bounds.Contains(child.position))
                return child;
        }

        return null;
    }
}

이제 생성한 브러쉬에 프리셋을 저장할 수 있으며 해당 브러쉬로 그린 오브젝트도 지우개를 이용하여 쉽게 지울 수 있다.


Uploaded by N2T