Grid
Tilemap이나 셀 기반 배치를 사용할 때 격자(Cell) 기반의 좌표 시스템을 정의하는 역할을 하는 유니티의 기본 제공 컴포넌트로, 유니티의 일반적인 Transform 좌표와 달리, 셀 단위로 오브젝트를 배치하는 방식을 제공한다.
간단히 말하면 Grid는 Tilemap을 배치하는 기준 좌표 역할을 하고, Tilemap이 셀 단위로 정렬되도록 만들어 격자 기반의 게임을 쉽게 구현할 수 있게 한다.
주요 속성
Cell Size | 각 셀의 크기를 조정 (기본값 1*1) |
Cell Gap | 셀 간의 간격을 설정 (기본값 0) |
Cell Layout | 격자 배치 방식 (Rectangle, Hexagon, Isometric) |
Cell Swizzle | 좌표 변환 방식 (XYZ 순서 변경) |
Tilemap
- 타일 기반의 2D 맵을 생성하는 유니티의 시스템 중 하나로, 기본적으로 Grid 컴포넌트가 포함된 게임 오브젝트에 추가되어 여러 개의 타일을 배치하고 관리할 수 있다.
- 타일을 추가하고 편집하기 위해 Tile Palette를 사용하며, 타일의 위치는 Grid의 셀 단위로 조정된다.
- Tilemap은 단순히 타일 데이터를 저장하는 역할을 하고, 이를 렌더링하기 위해 Tilemap Renderer가 필요하다.
- 물리적 충돌을 처리하기 위해 Tilemap Collider 2D를 추가할 수 있다.
Tilemap Renderer
- Tilemap이 관리하는 타일들을 화면에 렌더링하는 역할을 한다.
- 타일을 카메라에 올바르게 그려주며, 정렬 방식(레이어, 투명도 등)을 설정할 수 있다.
(Tilemap Renderer가 없으면 타일이 화면에 표시되지 않음)
- Sprite Renderer와 비슷한 역할을 하지만, Tilemap 전용으로 설계되었다.
Tilemap Collider 2D
- Tilemap에 충돌 박스를 생성하는 컴포넌트로, 충돌 처리를 해야 하는 경우 필수적으로 추가해야 하며 Tilemap에 배치된 타일 개별적으로 콜라이더를 자동으로 생성한다.
- 각 타일마다 개별적인 콜라이더가 생성된다. (타일 개수가 많으면 성능 문제 발생 가능)
- Composite Collider 2D와 함께 사용하면, 여러 개의 타일을 하나의 큰 충돌 영역으로 합칠 수 있다. (성능 개선)
- Composite Collider 2D와 함께 사용할 때는 Used By Composite 옵션을 체크해야 한다.
Composite Collider 2D
- 여러 개의 콜라이더를 하나의 단일 콜라이더로 합쳐주는 컴포넌트이다.
-Tilemap Collider 2D와 함께 사용하면 타일마다 개별 충돌 박스가 생성되지 않고 부드러운 경계를 가진 하나의 충돌 박스로 변환된다.
- 성능을 향상시키고 충돌 계산을 단순화하는 데 유용하다.
Rigidbody 2D
- 물리 연산을 적용하는 컴포넌트로, Rigidbody2D를 추가하면 중력, 힘, 속도 등의 물리 속성을 적용할 수 있다.
- Tilemap 자체에는 기본적으로 필요하지 않지만 Tilemap Collider 2D와 함께 사용하면 물리적 충돌을 처리할 수 있다.
- Tilemap Collider 2D를 Composite Collider 2D와 함께 사용할 때는 Rigidbody2D를 반드시 Static으로 설정해야 한다.
사용 방법 정리
1) Tilemap Collider 2D 추가
2) Composite Collider 2D 추가
3) Tilemap Collider 2D에서 Used By Composite 체크
4) Rigidbody2D 추가 후 Body Type을 Static으로 설정
※ 주의 사항
* Tilemap Collider 2D만 사용하면 타일 개별 충돌이 발생해 성능 저하가 있을 수 있다.
* Composite Collider 2D를 사용하면 충돌 영역이 단순화되므로 세밀한 충돌 처리가 필요한 경우 주의해야 한다.
Grid와 Tilemap
Grid(여기서는 Ground) 는 단독으로 사용되지 않고, Tilemap의 부모 오브젝트로 존재해야 한다.
또한, Tilemap을 배치할 때 기준 좌표 역할을 하며 모든 Tilemap 이 Grid의 설정을 따르게 된다.
위와 같이 여러 개의 Tilemap을 추가하면 같은 Grid 좌표 시스템을 공유할 수 있다.
활용할 수 있는 게임 유형
탑다운 슈팅, 로그라이크/로그라이트, 턴제 전략, 퍼즐, 2D 플랫포머, 도트 기반 게임 등 맵이 격자형(Grid-based)으로 정렬되거나, 일정한 패턴을 따라야 하는 게임이라면 거의 모든 장르에서 활용할 수 있다.
Reposition.cs
*타일맵(Ground)과 적(Enemy)**을 플레이어의 위치를 기준으로 자연스럽게 재배치하는 역할을 한다.
플레이어가 이동하면 설정한 조건문에 따라 배경(타일맵)과 적들이 보이지 않는 곳에서 다시 나타나도록 한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Reposition : MonoBehaviour
{
Collider2D coll; // 현재 오브젝트의 충돌체(Collider2D)를 저장하는 변수
void Awake()
{
coll = GetComponent<Collider2D>(); // 초기화
}
/* 기존 코드의 문제점
* 플레이어의 이동 방향을 GameManager.instance.player.inputVec에서 가져와 이동 방향을 결정
* 하지만 입력값은 순간적인 방향만을 나타낼 뿐, 항상 정확한 위치 관계를 반영하지 못할 수도 있음
* 즉, 플레이어가 이동하지 않더라도 inputVec 값이 Vector3.zero라 이상한 동작이 나올 수도 있음 */
/* 개선된 코드의 변화
* 새 코드에서는 "플레이어가 어느 방향에 있는지" 를 직접 계산하는 방식
* playerPos.x - myPos.x -> 플레이어가 타일맵보다 왼쪽에 있으면 음수, 오른쪽에 있으면 양수
* playerPos.y - myPos.y -> 플레이어가 타일맵보다 아래 있으면 음수, 위에 있으면 양수
* 이렇게 하면 입력값과 상관없이 타일맵이 항상 플레이어를 따라 자연스럽게 이동할 수 있음 */
// OnTriggerExit2D = Trigger가 체크된 Collider에서 나갔을 때 발생
void OnTriggerExit2D(Collider2D collision)
{
// OnTriggerExit2D의 매개변수인 상대방 Collider의 태그를 조건으로
// 플레이어가 설정된 'Area' 태그를 벗어났을 때만 실행
if (!collision.CompareTag("Area"))
return; // 필터 역할, Area 태그가 아니라면 함수 탈출
// 이 2개를 비교해서 플레이어가 어느 방향에 있는지 확인
Vector3 playerPos = GameManager.instance.player.transform.position; // 플레이어 위치
Vector3 myPos = transform.position; // 현재 오브젝트(타일맵 or 적)의 위치
switch (transform.tag) {
// Tilemap 재배치
case "Ground":
// 플레이어와 Tilemap의 X와 Y 위치 차이를 계산
// 플레이어가 왼쪽에 있으면 diffX는 음수, 오른쪽이면 양수
// 플레이어가 아래에 있으면 diffY는 음수, 위에 있으면 양수
float diffX = playerPos.x - myPos.x;
float diffY = playerPos.y - myPos.y;
// Tilemap이 이동해야 할 방향을 정하는 변수
// diffX가 음수면 dirX = -1(왼쪽으로 이동), 양수면 dirX = 1(오른쪽으로 이동)
// 3항 연산자 (조건) ? (true일 때 값) : (false)일 때 값
float dirX = diffX < 0 ? -1 : 1;
float dirY = diffY < 0 ? -1 : 1;
// Mathf.Abs = 음수를 양수로 바꿔 절대값을 반환하는 함수
// diffX와 diffY가 음수라면 아래 조건문에서 비교가 어렵기에
// 거리 차이의 크기만 비교하기위해서 해당 함수 사용
diffX = Mathf.Abs(diffX);
diffY = Mathf.Abs(diffY);
// 두 오브젝트의 거리 차이에서 X축이 Y축보다 크면 수평 이동
if (diffX > diffY) {
// Translate = 지정된 값 만큼 현재 위치에서 이동, 이동할 양을 입력
// Vector3.right = X축 방향(오른쪽)을 나타내는 단위 벡터(1, 0, 0)
// (Vector3.left * 1 * -40)과 똑같이 작동하나 전자가 직관적이기에 사용
transform.Translate(Vector3.right * dirX * 40); // dirX 방향으로 40만큼 이동
}
// Y축이 크면 경우 수직 이동
else {
// Vector3.up = Y축 방향(위쪽)을 나타내는 단위 벡터 (0, 1, 0)
// 오브젝트를 위쪽으로 이동할 때 사용
transform.Translate(Vector3.up * dirY * 40); // dirY 방향으로 40만큼 이동
}
break;
// 너무 멀어진 적(Enemey) 재배치
case "Enemy":
if (coll.enabled) // 오브젝트가 비활성화된 상태라면 재배치하지 않음
{
Vector3 dist = (playerPos - myPos) * 2; // 화면 바깥으로 재배치하기위해 플레이어와 적 사이의 거리를 거리를 2배로 늘림
// Random.Range(min, max) = min 이상 max 이하의 랜덤한 값을 반환하는 함수
// -3f ~ 3f 사이의 랜덤한 실수(float)를 반환
Vector3 ran = new Vector3(Random.Range(-3f, 3f), Random.Range(-3f, 3f), 0); // 예측이 어렵도록 범위 내 랜덤한 위치 오차를 추가
transform.Translate(dist + ran); // 기존 위치에서 dist + ran 만큼 위치 이동
}
break;
}
}
}
'Unity > Undead Survivor' 카테고리의 다른 글
열거형(enum) / 월드 좌표(World Position)와 스크린 좌표(Screen Position) / HUD(Head-Up Display) (0) | 2025.03.18 |
---|---|
범위 감지(Scanner) / 무기(Weapon)와 총알(Bullet) (0) | 2025.03.18 |
배열과 리스트의 차이 / 오브젝트 풀링(Object Pooling) (0) | 2025.03.17 |
코루틴(Corutine) / 적 생성(Enemy, Spawn) (0) | 2025.03.13 |
유니티(Unity)의 주요 이벤트 함수(Event Functions) (0) | 2025.03.12 |