Layer와 Tag 비교
게임 오브젝트를 비교하는 방법은 Layer과 Tag 설정이 있다.
Layer는 총 32개로 정의되어 있다. 32라는 숫자는 int형 즉, 비트형을 가져온다. 여기서 비트 연산으로 layer 처리를 해주는 개념으로 이해하면 된다. 비트형이기 때문에 0과 1로 입력/출력 값을 결정해준다.
Tag와 Layer은 다음과 같이 사용할 수 있다. 전부 다 같은 동작이 실행되고 각 코드마다 약간의 성능차이는 있다.
if(collision.gameObject.CompareTag("Player")) // 전부 다 같은 개념
if(collision.gameObject.name.Contains("Player"))
if(collision,gameObject.tag == "Player")
if(collision.gameObject.layer == 8)
if(collision.gameObject.layer == LayerMask.NameToLayer("Player"))
Layer 설정에 사용되는 비트 연산
void ShootRay()
{
// Ray를 이용해서 총알 발사
Ray ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward);
// Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// 나만 충돌하지 않도록 하고 싶다
int layer = 1 << gameObject.layer; // 나만 추출하는 코드, 100000(1만 충돌체크), int는 32개의 비트
RaycastHit hitInfo;
// Ray를 발사해서 만약 부딪혔다면
if(Physics.Raycast(ray, out hitInfo, 1000, ~layer)) // layer만 빼고, !은 bool 연산자, ~는 layer 연산자, 011111
{
// 부딪힌 지점에 파편 튀게 하고싶다
// 부딪힌 지점으로 이동시키기
bulletImpact.position = hitInfo.point;
// 파편이 튀는 방향을 부딪힌 지점이 향하는 방향과 일치시켜준다
bulletImpact.forward = hitInfo.normal;
// 파편효과 재생하기
bulletPS.Stop();
bulletPS.Play();
}
}
다음은 유니티에서 FPS 게임을 만들 때 Ray 발사와 관련된 코드이다. 여기서 layer와 관련된 내용을 작성해보고자 한다.
유니티에서 Layer는 보통 충돌 체크 상황에 사용되고 주로 비트 연산을 활용하고 있다.
int layer = 1 << gameObject.layer;
코드에서 layer 변수를 int형으로 선언해준 이유는 int 자료형이 32 bit(4 byte)의 데이터 크기를 가지고 있기 때문이다. 다음 사진과 같이 유니티 에디터 상에서 add layer 탭을 누르면 32개의 layer을 지정할 수 있는 이유가 바로 int 타입과 관련이 있기 때문이다.
int는 32bit의 데이터 크기를 가지고 있는데, 이를 다음과 같이 00000000000000000000000000000000(32개)의 비트 연산으로 표기할 수 있다. 비트 연산의 핵심은 0과 1이므로 원하는 layer 위치에 1을 할당하여 해당 layer의 동작 여부를 확인할 수 있다. 아울러, layer0 부터 2^0, layer1 = 2^1, layer2 = 2^2 와 같이 2진수를 사용하여 비트 연산에 활용할 수 있다.
int layer = 1 << gameObject.layer;
위의 코드는 gameObject.layer에 1을 넣어준 것을 의미하며 layer 6에 1의 값이 들어갔으니 000...001000000 와 같이 표현할 수 있겠다. 즉, << 비트 연산자를 통해 오른쪽부터 6번을 움직인 자리에 1을 할당 한 것(1 << 6)이다. 비트 연산자와 문법에 관련한 기본적인 내용은 여기서 다루지는 않겠다.
if(Physics.Raycast(ray, out hitInfo, 1000, ~layer))
raycast() 함수에서 1000m 이내에서 ray를 쏘는 코드를 작성하면 ray가 player 본인한테까지 발사될 수 있다. 이러한 경우
"~" 연산자를 사용해주어 player를 제외한 모든 오브젝트에 ray의 충돌 체크가 가능해진다. 참고로 부정을 뜻할 때 !가 bool 연산자라면, ~는 layer 연산자라고 생각하면 된다. ~layer을 선언했으니 111...110111111으로 비트 연산 값이 바뀌게 된다.
유니티 게임 개발 시 비트 연산 활용법
사실 최근 트렌드는 비트 연산을 많이 사용하지 않기는 한다. 하지만 비트 연산이 가지고 있는 장점들이 있기에 유니티에서는 비트 연산을 활용한 기능들을 제공하고 있다. 해당 기능을 살펴보기에 앞서 비트 연산을 게임 개발에 적용해볼 만한 예시를 살펴보자.
우리가 철권을 플레이 할 때, 고급 스킬 또는 연속기 등을 사용하려면 여러 방향키와 공격 키를 매우 짧은 시간 내에 연달아 또는 동시에 입력해야 한다. 입력 하나라도 미스가 난다면 해당 기술은 발동되지 않으므로 고도의 집중력이 필요한다. 이를 개발 상에서 구현할 때 우리는 보통 if문 또는 for문을 생각해 볼 수 있다. 키 입력과 관련하여 bool 타입 변수를 선언하고 if문 안에서 Keycode.A == true && Keycode.B == true ... 처럼 if문과 boo 변수를 남발해서 사용하는 게 일반적인 아이디어인데 매우 복잡하고 효율적이지 않는 코드가 될 것이다.
특히, 이런 경우 비트 연산을 활용하면 매우 간결하게 복잡한 키 입력을 표현해낼 수 있다.
아이디어는 다음과 같다. 키를 입력해야 하는 부분에 1을 할당하고 그렇지 않는 부분에 0을 할당해서 다음과 같이 00011110 이라는 비트 타입의 키 입력 데이터를 가지고 왔다. 그리고 플레이어의 키 입력을 & 연산자로 더해줘 동일한 값이 나오면 스킬이 발동되고, 그렇지 않으면 실패되도록 하면 된다. 다시 말해, 플레이어가 0001110 입력을 성공하였고 미리 정해진 키 입력 값인 0001110을 & 연산으로 더해주면 그대로 0001110이 나오게 된다. 반대로 플레이어가 0000110을 입력해서 & 연산해준다면 0000110 값이 최종적으로 산출되기 때문에 스킬이 발동하지 않을 것이다. 이렇게 복잡한 키 입력도 비트 연산을 통해 판정해 준다면 매우 쉽게 나타낼 수 있게 된다.
비트 연산은 if문을 남발해야 하는 경우 획기적으로 코드를 단축시켜줄 수 있는 훌륭한 방법 중 하나이다. 최근 트렌드에서 비트 연산을 많이 쓰지는 않지만 유니티에서는 layer 충돌 체크, Navmesh Agent에서 지형 오브젝트 상태 레이어 설정, Camera의 culling mask 기능 사용 등 몇몇 상황에서 비트 연산을 채택하고 있다.
'게임 프로그래밍 > 유니티 프로젝트' 카테고리의 다른 글
[Unity] OnDrawGizmos() 함수를 사용하여 시각적으로 범위 체크하기 DrawLine, DrawRay (0) | 2022.08.05 |
---|---|
[Unity] 타겟을 향한 오브젝트 회전, 캐릭터 컨트롤러 이동(transform.rotation, Quaternion.Lerp, Quaternion.LookRotation) (0) | 2022.08.05 |
[Unity] Level Design 레벨디자인 파이프라인 (0) | 2022.07.28 |
Unity Engine의 그래픽 연산 과정에 대한 이해(DirectX, OpenGL, MeshRenderer, MeshFilter) (0) | 2022.07.28 |
[Unity] Joystick 제작 원리 (0) | 2022.07.20 |