개?발/Unity 혼공

유니티 Tilemap 좌표 값 및 중앙 위치 구하기

YUEIC 2024. 8. 12. 20:37

캡슐이 플레이어고 아래 타일을 한칸 씩 움직이게 하려할 때 좌표를 구해야할 것이다.

알아보니 3D에서도 패키지만 설치하면 2D와 동일하게 Tilemap을 사용할 수 있어서 위와 같이 타일을 임시로 생성했다.

[참고링크]

 

[Unity] 3D 맵 제작 (2D 타일맵을 이용하여 제작하기)

궁금증이 들었던 부분 2D에서 처음 타일맵을 배웠을때 내가 오브젝트를 하나하나 만들 필요가 있던게 아니라 그림그리듯 배치를 해주면 됐어서 좋았는데 이걸 3D 맵 배치에서도 사용할 수 있을

milkyquartz.tistory.com

 

이제 타일맵 오브젝트로부터 타일의 각 위치를 먼저 알아야한다. 그래야 이동할 다음칸이나 목적지를 정할 수 있기 때문이다.

 

처음 그림에 좌표를 빗대어 보면 이렇게 표현할 수 있다. 일단 여기서 알아두어야할 것이 그림에 (0,0) 이라고 붉은 글씨로 적힌 부분이 실제로 World 좌표 (0,0,0) 이다. Tilemap을 생성할때 일부러 해당위치를 시작점으로 잡기 위해 1사분면을 중심으로 생성했다.

 

Local To Cell, World To Cell

시작단계라 플레이어가 서있는 부분 아래에 타일을 Ray로 감지하여 타일의 좌표를 알아보자.

    public int[] PlayerCrdn;    //현재 플레이어가 존재하는 위치
    public Tilemap tilemap; //타일맵을 담을 변수
    RaycastHit rayHit;      //타일맵을 감지하는 RayHit
    
    void Update()
    {
        DetectTileMap();
    }
    
    void DetectTileMap(){
    	Debug.DrawRay(transform.position, Vector3.down, Color.red);                 //Ray 가시화
    	if(Physics.Raycast(transform.position, Vector3.down, out rayHit)){          //타일맵이 스캔되면
    	}
    }

 

rayHit 변수는 전역변수로 선언하고

타일맵을 감지하는 부분을 DetectTileMap() 으로 따로 분리했다.

그리고 그 안에 Ray관련 이벤트를 생성했다.

 

실제 Ray는 보이지 않지만 DrawRay를 통해 위와 같이 아래를 향하는 Ray를 볼 수 있다.

 

이제 타일을 감지하려면 rayHit에 저장된 오브젝트의 위치를 매개변수로 하여 Vector3Int형으로 반환되는 Local To Cell 혹은 World To Cell 메서드가 필요하다.

 

둘 다 (x, y)값을 반환하지만 조금 다르다.

Local To Cell은 타일 한칸의 크기가 1이 되든 10이 되든 (0, 0)의 오른쪽에 있는 타일은 (1, 0)이 된다.

그에 반해 World To Cell은 타일 한칸의 크기에 영향을 받는다.

예를 들어 타일 한칸의 크기가 3 이라면 (0, 0)의 오른쪽에 있는 타일은 (3, 0)이 된다.

 

 

지금 필요한건 Local To Cell 이므로 하나만 사용한다.

 

    public int[] PlayerCrdn;    //현재 플레이어가 존재하는 위치
    public Tilemap tilemap; //타일맵을 담을 변수
    RaycastHit rayHit;      //타일맵을 감지하는 RayHit
    
    void Update()
    {
        DetectTileMap();
    }
    
    void DetectTileMap(){
    	Debug.DrawRay(transform.position, Vector3.down, Color.red);                 //Ray 가시화
    	if(Physics.Raycast(transform.position, Vector3.down, out rayHit)){          //타일맵이 스캔되면
    	Vector3Int cellCodn = tilemap.LocalToCell(rayHit.transform.position);   //스캔된 타일의 좌표
        Debug.Log("로컬칸좌표 : " + cellCodn);            				//타일맵 내에서 좌표정보 출력
        }
    }

 

rayHit의 좌표를 매개변수로 하여 타일맵의 메서드 LocalToCell를 호출하고 Vector3Int형 변수에 저장했다.

그리고 그걸 출력하도록 했다.

 

 

위와 같이 0,0 칸에 존재할때는 (0,0,0)

 

 

플레이어의 위치를 임의로 옮기자 (3,2,0)으로 출력된다.

이제 이 좌표만 존재하면 될까?

그렇지 않다.

해당 좌표대로 플레이어를 이동시킬 경우 (0,0)좌표에 존재하는 칸 위에 올라가는것이 아니라 타일맵 칸의 좌측 하단으로 이동할 것이다.

월드 좌표는 타일맵의 좌측하단이기 때문이다.

그래서 감지된 타일맵의 정중앙위치를 가리키는 월드좌표가 필요하다.

 

GetCellCenterLocal

 

위 Local To Cell 메서드를 통해 알아낸 것은 위 그림의 파란색 글씨 값이다. 하지만 실제로 파란색 글씨의 값으로 플레이어를 이동시켰다간 각 칸의 모서리에 있는 검은 글씨의 좌표로 이동하게 될 것이다.

 

따라서 그 칸의 중심 값을 반환하는 GetCellCenterLocal 메서드를 사용해야한다.

    public int[] PlayerCrdn;    //현재 플레이어가 존재하는 위치
    public Tilemap tilemap; //타일맵을 담을 변수
    RaycastHit rayHit;      //타일맵을 감지하는 RayHit

    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
        DetectTileMap();
    }

    void DetectTileMap(){
        Debug.DrawRay(transform.position, Vector3.down, Color.red);                 //Ray 가시화
        if(Physics.Raycast(transform.position, Vector3.down, out rayHit)){          //타일맵이 스캔되면
            Vector3Int cellCodn = tilemap.LocalToCell(rayHit.transform.position);   //스캔된 타일의 좌표
            Vector3 cellCenter = tilemap.GetCellCenterLocal(cellCodn);              //스캔된 타일의 중앙 Position
            Debug.Log("로컬칸좌표 : " + cellCodn + "좌표 중앙 : " + cellCenter);         //타일맵 내에서 좌표정보 출력 
        }
    }

 

이전 코드에 GetCellCenterLocal 메서드 코드를 추가했다.

해당 메서드는 이전에 구했던 Vector3Int 형의 좌표값을 매개변수로 하여 호출하면 해당 좌표의 중심값을 Vector3 형으로 반환한다.

그 값을 칸 좌표와 함께 출력하도록 구성했다.

 

 

이후 좌표의 중앙값이 정상적으로 출력된다.

 

이제 이걸로 플레이어를 움직이도록 하면 될 것 같다.

 

 

 

타일맵 관련 유용할 것 같은 메서드들

 

Unity - Tilemap Properites 및 관련 메서드

Tilemap Properties 01 animationFrameRate 타일맵 내 모든 타일의 애니메이션 프레임 속도이다. 애니메이션의 재생 속도를 조절할때 사용한다. public float animationFrameRate { get; set; } 02 cellBounds 타일맵 내에서

code-piggy.tistory.com