스파르타 게임개발종합반(Unity)/TIL - 본캠프 매일 공부 기록

2024.06.20 TIL - 유니티 아이소메트릭(Isometric) 타일맵(Tilemap)에서 오브젝트 랜덤 생성하기

테크러너 2024. 6. 20.

2D에서 랜덤 좌표 x,y를 타일맵에서 가져오기 위한 고민

출처 : https://docs.unity3d.com/kr/current/Manual/Tilemap-Painting.html

내가 오늘 하고 싶었던건 타일맵 위에 아이템을 랜덤으로 스폰하는 것이었다.

 

일반적인 타일맵직사각형 형태의 `x, y`가 명확한 형태이다.

그래서 그냥 타일맵의 `x, y`의 최소~최대값 사이의 랜덤값을 뽑으면 됐다.

 

그런데 위와 같은 아이소메트릭 형태의 타일맵은 그냥 x, y값을 가져와도 되는건가? 의문이었다.

 

 

생각해본 첫 번째 방법

2024.06.05 - [스파르타 게임개발종합반(Unity)/TIL - 본캠프 매일 공부 기록] - 2024.06.05 TIL - MenuItem, 유니티 메뉴창에 툴 구현하기

 

▲ 지난번에 오브젝트에 자동으로 박스 콜라이더를 부착하는 툴을 만든 적이 있다.

그때 사용했던 방식 중, 오브젝트의 스킨 랜더러의 `bounds`를 받아와 경계의 최소~최대값을 알 수 있었다.

 

그러면 `TileCollider2D`의 `bounds`를 받아오면 되지 않을까? 생각했다.

그런데 타일맵의 콜라이더는 그려야한다...!

그래서 자동으로 바닥의 콜라이더를 그려주는 툴을 만드려고 했다.

 

그런데 이게 이렇게 복잡해질 일인가? 더 쉬운 방법은 없을까? 고민했다.

 

 

생각해본 두 번째 방법

파란색 동그라미가 꼭짓점으로 된 네모 영역안이 타일맵이다.

 

`Tilemap`이 위의 그림에서 네모 영역이고, `Tilemap Renderer`가 그려진 초록색 타일맵영역이다.

 

내가 원하는건 초록색 영역이니까  `Tilemap Renederer`의 `bounds`를 받아오면 되지 않을까?

아.. 그런거 없음~ ㅋㅋ

 

이리저리 찾아보니 타일맵 안의 타일들 정보를 알고 있는건 `Tilemap`이고, `Tilemap Renderer`는 타일 정보를 가지고 있지 않다.

그래서 `Tilemap`안의 타일들을 검사해서 존재하는 타일(초록색 타일)인지 확인하고, 해당 타일의 좌표값을 받아오면 됐다!

 

    public Tilemap SpawnRange;

    private List<Vector3Int> validTilePositions = new List<Vector3Int>();

    private void FindValidTilePositions()
    {
        BoundsInt bounds = SpawnRange.cellBounds;

        for (int x = bounds.xMin; x < bounds.xMax; x++)
        {
            for (int y = bounds.yMin; y < bounds.yMax; y++)
            {
                Vector3Int tilePosition = new Vector3Int(x, y, 0);
                if (SpawnRange.HasTile(tilePosition))
                {
                    validTilePositions.Add(tilePosition);
                }
            }
        }
    }

타일맵 영역 == `SpawnRange`

타일맵 한 칸 == `SpawnRange.cellBounds`

 

`2D`인데 왜 `Vector3`인거지? 의문이었는데, 타일의 위치를 `Vector3Int`로 표현한다고 한다.

일반적인 직사각형 타일맵이었으면 `Vector2`로 해도 될 것 같은데, 아이소 매트릭이다보니 정확한 `x, y`좌표가 필요해서인 것 같다.

 

`SpawnRange.HasTile`을 통해 타일이 있는지 검사할 수 있다.

 

`FindValidTilePositions()`는 `Start()`에서 미리 유효한 타일 검사를 해뒀다.

스폰할 때마다 검사하면 비용이 낭비된다고 생각했다.

그래서 미리 검사한 후 유효한 타일의 위치들을 리스트에 담아뒀다.

 

    private Vector3 ReturnRandPos()
    {
        Vector3 randomPos = Vector3.zero;

        if (validTilePositions.Count > 0)
        {
            Vector3Int randomTilePos = validTilePositions[Random.Range(0, validTilePositions.Count)];
            randomPos = SpawnRange.CellToWorld(randomTilePos);
        }

        return randomPos;
    }

리스트에 담아둔 위치에서 랜덤 좌표를 뽑아오는데 주의할 점이 있다.

`SpawnRange.CellToWorld`를 통해 타일 좌표를 월드 좌표로 변환해줘야 한다.

이유는 타일맵에서는 각 타일이 그리드 상에 위치하며, 이 위치를 타일 좌표로 표현하기 때문이다.

월드에 있는 타일 좌표를 알아야하기 때문에 월드 좌표로 변환하는 것이다.

반응형

댓글