해당 게시물은 유니티에서 레이캐스트를 어떤 식으로 활용할 수 있는지 정리한 게시물입니다.
레이캐스트는 정확한 물리처리를 요구할 때 사용합니다. 2D 플랫포머 게임에서 바닥을 체크할 때, FPS 게임에서의 총알 데미지, 등등 활용되는 방식은 여러가지 입니다. 지금부터 어떻게 사용되는지 간단히 알아보겠습니다.
레이캐스트 간단 설명
어떤 위치에서 광선을 발사하여 그 광선에 닿는 물체가 있는지 검사하는 방식. RaycastHit 을 사용하여 여러가지 값도 쉽게 가져올 수 있어서 많이 사용하는 방법입니다.
유니티 스크립팅 API
https://docs.unity3d.com/kr/530/ScriptReference/Physics.Raycast.html
Physics.Raycast(vector3 시작점,vector3 방향,float 최대거리,layerMask 레이어마스크);
보통 레이캐스트는 위에서 처럼 사용됩니다. 하지만 유니티 스크립팅을 보면 훨씬 다양하게 사용할 수 있으니 한 번은 읽어보는 게 좋습니다.
눈앞의 사물을 감지하고 옮길 수 있는 기능을 만들어보자

지금부터 설명할 방법은 1인칭 시점 3D 캐릭터 기준으로 설명합니다. 1인칭 시점 캐릭터는 메인 카메라를 가지고 있어 직접 움직이면서 게임 세상을 볼 수 있는 특징을 가지고 있습니다.
캐릭터가 가지고 있는 메인 카메라를 활용하여 직접 움직이면서 Raycast 로 물건을 옮기는 기능을 만들어 보겠습니다.
1. Raycast 를 통해 광선을 쏘고 게임 오브젝트를 감지하자
// 카메라를 받을 변수
private Camera playerCam;
// 광선거리
public float distance = 100f;
void Start()
{
// 스타트 함수를 통해 카메라를 받습니다
playerCam = Camera.main;
}
void Update()
{
// 본문 설명 참조
Vector3 rayOrigin = playerCam.
ViewportToWorldPoint(new Vector3(0.5f, 0.5f, 0));
Vector3 rayDir = playerCam.transform.forward;
// Scene 창에서만 보이는 선을 발사합니다
// 레이케스트 광선 범위 확인용입니다
Debug.DrawRay(rayOrigin, rayDir*distance, Color.red);
// 마우스 왼쪽 버튼을 통해 레이캐스트 발동
if(Input.GetMouseButtonDown(0))
{
if(Physics.Raycast(rayOrigin, rayDir, distance))
{
Debug.Log("광선에 맞았다!!");
}
}
}
스크립트를 만들어서 코드를 작성합시다. 위 코드는 메인 카메라를 통해 광선을 발사하여 게임 오브젝트를 감지하는 코드입니다.
위 코드에서 눈여겨 봐야하는 부분은 playerCam.ViewportToWorldPoint 입니다.
Raycast는 광선이 발사되는 원점 Vector3 좌표를 요구합니다. 위 코드는 메인 카메라가 Raycast를 발사되게 작성되었고 광선이 발사되는 위치는 메인 카메라의 좌표가 됩니다.
ViewportToWorldPoint 는 유니티 카메라의 내장된 함수인데 카메라의 위치를 찍어줍니다. Vector3(0.5f, 0.5f, 0) 은 화면 정중앙을 의미합니다.
위 스크립트를 가지고 있는 1인칭 시점의 캐릭터는 정상적으로 Raycast를 통해 오브젝트를 인식(물리처리)할 것입니다. 하지만 문제가 있습니다. 원하는 오브젝트만 물리처리 하는 것이 아니라 모든 오브젝트를 물리처리하죠.
2. 레이어를 활용하여 원하는 오브젝트만 Raycast 에 처리되게 하자

유니티의 게임 오브젝트들은 인스펙터 창에서 Layer(레이어) 설정을 할 수 있습니다.
Raycast 에 물리처리되게 하고싶은 게임 오브젝트들을 적당한 레이어를 선택해 주시면 됩니다. 그리고 당연히 스크립트를 수정해야 합니다.
private Camera playerCam;
public float distance = 100f;
// 레이어 선택을 위한 변수
public LayerMask whatIsTarget;
void Start()
{
playerCam = Camera.main;
}
void Update()
{
Vector3 rayOrigin = playerCam.
ViewportToWorldPoint(new Vector3(0.5f, 0.5f, 0));
Vector3 rayDir = playerCam.transform.forward;
Debug.DrawRay(rayOrigin, rayDir*distance, Color.red);
if(Input.GetMouseButtonDown(0))
{
// LayerMask 변수인 whatIsTarget 을 추가하자
if(Physics.Raycast(rayOrigin, rayDir, distance, whatIsTarget))
{
Debug.Log("광선에 맞았다!!");
}
}
}

LayerMask 타입의 변수는 현재 생성되있는 레이어를 인스펙터에서 선택할 수 있습니다. 물론 퍼블릭으로 선언해야 인스펙터에서 선택할 수 있겠죠.
저는 Raycast에 물리처리 되게 하고싶은 게임 오브젝트의 Layer를 위 사진과 같은 레이어로 설정했었습니다. 해당 레이어를 인스펙터에서 LayerMask 변수에 대입시키면 됩니다.
코드에서 레이캐스트 함수에 레이어마스크 파라미터를 추가했기 때문에 레이캐스트는 설정했었던 레이어에 포함돼있는 오브젝트만 물리처리하게 됩니다.
3. RaycastHit 을 통해 광선에 닿은 게임 오브젝트의 정보를 가져와 게임 오브젝트를 옮기자
private Camera playerCam;
public float distance = 100f;
public LayerMask whatIsTarget;
// 이동시킬 게임 오브젝트 트랜스폼 변수
private Transform moveTarget;
// 해당 오브젝트의 거리
private float targetDistance;
void Start()
{
playerCam = Camera.main;
}
void Update()
{
Vector3 rayOrigin = playerCam.
ViewportToWorldPoint(new Vector3(0.5f, 0.5f, 0));
Vector3 rayDir = playerCam.transform.forward;
Debug.DrawRay(rayOrigin, rayDir*distance, Color.red);
// 레이캐스트힛 변수 선언
RaycastHit hit;
if(Input.GetMouseButtonDown(0))
{
if(Physics.Raycast(rayOrigin, rayDir, out hit, distance, whatIsTarget))
{
// out 키워드는 입력으로 들어온 값이 내부에서
// 어떠한 값이 생겨서 빠져나간다는 의미
GameObject hitTarget = hit.collider.gameObject;
Debug.Log("광선에 맞았다!!");
// 레이캐스트힛 으로 받아온 오브젝트 대입
moveTarget = hitTarget.transform;
// 게임 오브젝트와의 거리
targetDistance = hit.distance;
}
}
// 마우스 버튼 때면 moveTarget 변수 비우기
if(Input.GetMouseButtonUp(0))
{
moveTarget = null;
}
// moveTarget 에 값이 있을 시 오브젝트 이동
if(moveTarget != null)
{
moveTarget.position = rayOrigin + rayDir * targetDistance;
}
}
레이캐스트힛 으로 선언한 변수가 Update 함수안에 있습니다. Raycast 의 파라미터를 통해 RaycastHit 변수에 값을 대입시켰습니다.
RaycastHit 변수는 많은 정보를 담고 있습니다. Raycast 에 충돌처리된 오브젝트의 정보를 RaycastHit 으로 받아올 수 있는데 게임 오브젝트를 이동시키는 핵심이 RaycastHit 으로 받아온 게임 오브젝트의 값을 활용하는 것입니다.
그리고 Raycast 파라미터 중에 out 키워드가 있는데, out 키워드를 통해 RaycastHit 변수에 값이 대입되는 것입니다.