게임에서 충돌 처리는 매우 중요한 요소입니다. 유니티에서는 이러한 처리를 위해 Rigidbody 와 BoxCollider, CapsuleCollider 등의 Collider 컴포넌트를 제공해 줍니다.
1. Rigidbody
Rigidbody 는 GameObject 를 물리 엔진 기반으로 동작할 수 있게 합니다.
인스펙터 창에서 [Add Component > Physics > Rigidbody] 를 선택하여 컴포넌트로 추가할 수 있습니다. Rigidbody를 추가한 후 게임을 실행하면 해당 오브젝트가 밑으로 떨어집니다. 이는 물리 엔진의 중력이 적용됐기 때문입니다.
아래의 링크는 Rigidbody 에 대한 유니티 공식 매뉴얼입니다. 한글로 잘 정리되어 있으니 참조하시기 바랍니다.
https://docs.unity3d.com/kr/2020.3/Manual/class-Rigidbody.html
여기서는 오브젝트가 물리 엔진에 반응하지 않는 상태로 만들고 단지 다른 물체와의 충돌 여부를 판단하는 방법에 대해 알아보도록 할 것입니다.
2. Collider 컴포넌트
Collider 는 충돌 처리를 위해 게임 오브젝트에 특정 형태로 생성됩니다. 충돌 처리는 시스템에 많은 부하를 주기 때문에 최대한 단순한 모양의 collider 가 필요합니다. 또, 대부분의 경우에는 collider 가 사람이나 비행기 등 복잡한 메쉬의 외각을 감싸는 형태의 단순한 모양이더라도 플레이어가 어색함을 느끼지 않게 처리할 수 있습니다. 유니티가 제공하는 기본 collider에는 다음과 같은 종류가 있습니다.
3D Colliders | BoxCollider, SphereCollider, CapsuleCollider |
2D Colliders | BoxCollider2D, CircleCollider2D |
BoxCollider 컴포넌트는 큐브를 생성할 때 이미 추가되어 있습니다. 다만 BoxCollider 의 크기가 큐브와 완전히 동일하게 설정되어 있어서 씬 창에서도 잘 구분이 되지 않았을 뿐입니다.
인스펙터 창에서 BoxCollider 컴포넌트의 Size 를 (1.1, 1.1, 1.1) 로 변경하면 씬 창에서 큐브 주위에 보이는 초록색 테두리가 BoxCollider 입니다. 다시 Size를 (1, 1, 1) 로 변경해 줍니다.
유니티는 저 초록색 박스 영역에 다른 Collider 가 닿았는지 여부로 충돌 처리를 합니다. 즉, 유니티 엔진은 충돌 처리를 메쉬와 메쉬가 아닌 Collider와 Collider 끼리 하기 때문에 메쉬가 아무리 복잡해도 기본 Collider 를 사용한다면 적은 비용으로 수행할 수 있습니다.
* 유니티는 MeshCollider 도 지원합니다. 이것을 사용하면 Mesh 와 동일한 구조의 Collider 가 생성되지만 시스템에 많은 부하를 줄 수 있고 MeshCollider 끼리는 충돌 처리가 되지 않는 제약도 있습니다.
다시 위의 그림을 보면 IsTrigger 가 체크되어 있는 것이 보이실 겁니다. 이 옵션을 활성화하면 Collider 가 다른 Collider와 충돌했을 때 물리적 반응을 일으키지 않고 단지 충돌 여부만 확인할 수 있게 해줍니다.
3. 충돌 처리 실습
먼저 현재 씬에 있는 큐브의 이름을 "PlayerCube" 로 변경하겠습니다. 변경하는 방법은 Hierarchy 창에서 "Cube" 를 선택한 후 다시 한번 클릭하거나 F2 키를 누르면 수정할 수 있습니다.
또 다른 방법은 Cube 선택 후 인스펙터 창의 상단에 있는 Cube 단어를 클릭하면 수정할 수 있습니다.
충돌은 대상이 있어야 하니 새로운 큐브를 하나 더 생성하도록 합니다. (새로운 큐브 생성 방법은 [유니티 강좌] 오브젝트 생성과 기본 도구 사용법 을 참고해 주세요.) 생성된 큐브의 이름을 "ObstacleCube" 로 변경합니다.
이제 두 큐브의 Transform을 각각 다음과 같이 수정해줍니다.
다음으로 "PlayerCube"의 CubeHandler 코드를 아래와 같이 수정하도록 하겠습니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CubeHandler : MonoBehaviour
{
public float speed;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.LeftArrow))
{
transform.Translate(Vector3.left * speed * Time.deltaTime);
}
else if (Input.GetKey(KeyCode.RightArrow))
{
transform.Translate(Vector3.right * speed * Time.deltaTime);
}
}
private void OnTriggerEnter(Collider other)
{
print(string.Format("{0} 오브젝트가 {1} 와 충돌했습니다.", gameObject.name, other.gameObject.name));
}
private void OnTriggerExit(Collider other)
{
print(string.Format("{0} 오브젝트가 {1} 와 떨어졌습니다.", gameObject.name, other.gameObject.name));
}
}
코드에 새로운 OnTriggerEnter 와 OnTriggerExit 함수 두 개가 추가되었습니다. 이 이벤트 함수가 호출되기 위한 선행 조건은 다음과 같습니다.
- Rigidbody 컴포넌트 있어야 합니다.
- BoxCollider 나 SphereCollider 등 Collider 컴포넌트가 있고 IsTrigger 항목이 활성화되어 있어야 합니다.
다음은 이벤트 함수와 관련된 코드에 대한 설명입니다.
OnTriggerEnter | 두 오브젝트의 Collider 가 겹치는 부분이 생기는 순간 즉, 충돌이 감지되면 호출됩니다. 이 함수의 파라미터로 넘어오는 other 는 충돌한 다른 collider 의 정보를 갖고 있습니다. 이 예제에서 other 는 ObstacleCube의 BoxCollider 가 됩니다. |
OnTriggerExit | 두 오브젝트의 Collider 가 겹치는 부분이 사라지는 순간인 충돌 상태가 해제되면 호출됩니다. |
print() | 유니티 에디터 하단에 있는 Console 창에 메시지를 출력할 수 있는 기능을 제공합니다 |
string.Format() | C# 언어에서 문자열을 처리에 제공되는 함수입니다. |
gameObject.name | 현재 스크립트가 작성된 객체의 이름입니다. 여기서는 PlayerCube 입니다. |
other.gameObject.name | other 는 OnTriggerEnter 와 OnTriggerExit 의 함수 파라미터입니다. other 는 작성된 스크립트를 포함하는 객체와 충돌한 다른 객체를 의미합니다. 따라서 other.gameObject.name 은 충돌한 다른 객체의 이름입니다. |
Hierarchy 창에서 "PlayerCube"를 선택하고 인스펙터 창에서 CubeHandler 스크립트 컴포넌트의 Speed 필드 값을 10으로 설정하신 다음 게임을 실행시킵니다. 게임이 실행된 후 키보드의 방향키를 이용해 PlayerCube 를 ObstacleCube 에 충돌시키거나 떨어뜨리면 그에 맞는 메시지가 출력되는 것을 확인하실 수 있습니다.
함께 보면 좋을 글
'게임 프로그래밍 > 유니티(2021.3 LTS) 강좌' 카테고리의 다른 글
[유니티 기초] 프리팹 (Prefab) - 동기화 (2) | 2022.10.25 |
---|---|
[유니티 기초] 에셋 스토어 (Asset Store) 사용 (0) | 2022.10.24 |
[유니티 기초] 키보드, 마우스 입력 처리 (0) | 2022.10.20 |
[유니티 기초] 스크립트 직렬화 (Script Serialization) (0) | 2022.10.19 |
[유니티 기초] 오브젝트 회전과 Time.deltaTime (0) | 2022.10.18 |
댓글