Machineboy空

BubbleShooter 02: 공을 벌집 모양으로 배치하고 파괴해보자! (TileMap, Hexagrid, Collider2D) 본문

Game/개발 일지

BubbleShooter 02: 공을 벌집 모양으로 배치하고 파괴해보자! (TileMap, Hexagrid, Collider2D)

안녕도라 2024. 5. 11. 12:45

 

공들을 어떻게 위 그림처럼 벌집 모양 격자로 배치하는 걸까.

그리고 각 칸들의 정보를 알아내기 위해선 어떻게 해야하는걸까.

 

처음으로 생각했던 방식은 위치를 다 계산해서 2차원 배열로 좌표를 할당해두는 것.

하지만 직접 그리드를 다 그린다는 것이 얼마나 비효율적일지 시간을 가늠하다 접었다.

 

두번째 방식은, 검색하다 알아낸 tilemap이란 기능을 활용해보자는 것이었다.


01. 공 벌집 모양 배치 : TileMap, Tile Palette

tile Palette : 붓 버튼 - 그리기 / 지우개 버튼 - 지우기

 

  1. Tilemap - Hexagonal - Flat-Top 생성
    • flat-top :  변이 위로 향하는 것, point-top : 꼭짓점이 위로 향하는 것 (03장에서 hexagrid 좀 더 자세히 다룰 예정..)
  2. Tile Palette에서 새 palette생성 후 이미지 소스 불러와 배치하기.
  3. Tilemap Collider2D 컴포넌트 붙여주기!
    • 각 칸에 들어간 sprite모양대로 collider가 붙는다
    • 무슨 말이냐면, 타일맵 전체가 아니라 구슬 하나 하나마다 개별로 콜라이더가 붙는다는 뜻

 

*** 

Tile 사이즈 조절하는 법

 

타일 팔레트상 cell의 크기와 scene에서의 cell의 크기가 다름..

 

무슨 말이냐면, 타일 팔레트 상에서 이미지가 그리드 안에 다 들어간듯 보여도 직접 씬 화면에 도장찍어보면 너무 크게 찍히는 경우가 생김..

어디서 주워들은 바로 이미지 사이즈를 64px*64px로 맞춰주면 된다는 것 같은데, 해보지 않았다.

 

 

tile palette 선택 툴로 그리드 칸 선택 후 grid selection Properties의 scale값을 조절해주면 된다!

그리고 문제의 저 grid selection Properties - scale에 코드로 접근하는 방법.. 3장에서 소개한다. 찾아내기 참 어려웠다.


02. 개별 Tile에 접근하기 (★★★)

 

그래서 각 Tile에 충돌체크는 어떻게 할 것이며, 충돌한 tile의 각 좌표는 어떻게 얻어 올것인가.

 

tilemap 생성하고 배치하는 것까진 어찌저찌 했으나,

각 셀, tile의 좌표를 알아내는 방법을 찾는 게 정말 힘겨웠다.

 

개별 타일을 선택해보면, Position의 x, y값이 2차원 배열 상의 좌표인 것 같은데

도무지 이 값에 접근하는 방법을 모르겠는거다..

수많은 구글링 끝에, 그리드 셀 좌표 개념이 따로 있고, 이를 월드좌표로 치환해 값을 받을 수 있다는 것을 알게됌.

(사실 그 어느 곳에도 그런 정보가 있었던 건 아니고, 코드 보고 대충 파악함..)

 

tilemap.WorldToCell(vector2)

tilemap.CellToWorld(vector3Int) 요 두 가지 메소드로 서로 변환 가능함.

 

 

현재 상황

Ball 배치된 Balls
RigidBody2D TilemapCollider2D
Collider2D  

 

필수 메소드 알아두기!

 

- tilemap.WorldToCell(vector2)

- tilemap.GetTile(vector3Int)

- tilemap.SetTile(vector3Int)

 

그리고 collision2D에는 contact로 충돌 위치에 접근할 수 있다는 것..!

 // 부딪힌 딱 처음 위치 체크: other.contacts[0].point
 
 private void OnCollisionEnter2D(Collision2D other)
    {
        if (other.collider.CompareTag("TileMap"))
        {
        	//셀 좌표: Vector3Int <-> 월드 좌표: Vector2
            
            Vector3Int cellPos = tilemap.WorldToCell(other.contacts[0].point);
            TileBase hitTile = tilemap.GetTile(cellPos);

            if (hitTile != null)
            {
				tilemap.SetTile(cellPos, null);
            }
        }
    }
 // 부딪힌 모든 곳 체크하고 싶다면 other.contacts
 
 private void OnCollisionEnter2D(Collision2D other)
    {
        if (other.collider.CompareTag("TileMap"))
        {
        	foreach(ContactPoint2D contact in other.contacts)
            {
            	Vector3Int cellPos = tilemap.WorldToCell(contact.point);
                TileBase hitTile = tilemap.GetTile(cellPos);
                
                if(hitTile != null)
                {
                	tilemap.SetTile(cellPos, null);
                }
            }
        }
    }

 

이 간단해보이는 코드를 만들어내기까지 수많은 구글링과정이 있었음