[Unity] Raycast

Lingtea_luv·2025년 4월 17일
0

Unity

목록 보기
5/30
post-thumbnail

Raycast


Raycast(레이캐스트)는 시작지점에서 일직선 상으로 진행되는 가상의 레이저를 발사하고 레이저에 닿는 오브젝트를 검출하는 기능이다.

흔히 FPS에서 총알 궤적이나 적 감지할 때에 많이 사용되며, 게임 AI에서 시야 내에 적이 없는지 구분할 때에도 사용할 수 있다.

하지만 매 프레임마다 레이캐스트를 이용해 검사하는 것은 많은 연산을 소모하므로 대체할 수 있는 방법이 있는지 없는지 생각해보는 습관을 들이는 것이 중요하다.

활용

  • FPS 에임 : 탄두 발사 경로부터 에임 범위에 들어오는 사용자의 닉네임이 표시되는 기능 또한 레이캐스트를 사용한다.

  • 게임 내 오브젝트 선택과 상호작용
    게임내에서 마우스로 오브젝트를 선택할 수 있는 기능도 레이캐스트를 사용한다. 카메라로부터 시작된 레이캐스트에 닿는 오브젝트는 선택된 것으로 구현하는 것이다.

구현

public class RaycastTest : MonoBehaviour
{
	private void Update()
    {
    	// Raycast : 레이저를 발사하여 부딪히는 collider 감지(Boolean값)
        // RaycastHit : 감지된 collider의 정보(transform)
        // 10f : 레이저의 최대 거리(가시거리로 생각하면 편할 듯)
        if(Physics.Raycast
        (transform.position, transform.forward, out RaycastHit hitInfo, 10f))
        {
        	// 레이저에 닿은 collider가 있다면 이름 로그 출력
            Debug.Log($"{hitInfo.collider.gameObject.name} 감지");
        }
    }
}

실습 : 플레이어를 따라오는 몬스터

public class Monster : MonoBehaviour
{
	[SerializeField] Transform eyeTransform;
	[SerializeField][Range(0f,10f)] float sightRange;
    [SerializeField] float moveSpeed;
    
    private void Update()
    {
    	DetectTarget();
        if(target != null) Trace();      
    }
    
    private void DetectTarget()
    {
    	if(Physics.Raycast(eyeTransform.position, eyeTransform.forward, out RaycastHit hitInfo, sightRange)
        {
        	Debug.DrawLine(eyeTransform.position, hitInfo.point, Color.green);
            // 감지된 충돌체가 플레이어인지 확인하여      
            if(hitInfo.collider.gameObject.tag == "Player")
            {
            	// 감지된 충돌체를 타겟으로 지정
            	target = hitInfo.collider.gameObject;
            }   
            else
            {
            	// 쫓아오다가 장애물에 가리면 target 지정 해제
            	target = null;
            }
        }
        else
        {
        	Debug.DrawLine(eyeTransform.position, eyeTransform.position + eyeTransform.forward * sightRange, Color.green);
    		target = null;
        }
    }
    
    private void Trace()
    {
    	transform.position = Vector3.MoveTowards(transform.position, target.transform.position, moveSpeed * Time.deltaTime);
        transform.LookAt(target.transform.position);
    }
    
}
// 1. 이름 매치
hitInfo.collider.gameObject.name == "Player"
// 2. 태그 매치
hitInfo.collider.gameObject.tag == "Player"
// 3. component 소유 여부 확인
TankController tank = hitInfo.collider.gameObject.GetComponent<TankController>();
if(tank != null)
{
	// damage();
}

기타


Layer

Unity에서 Layer 및 LayerMask는 충돌 처리, Raycast 필터링 등에 사용된다.

Layer

게임 오브젝트를 분류하는 시스템으로 Unity에서는 0~31번까지 총 32개의 Layer를 제공한다. 기본으로 제공하는 Layer를 포함하여 나머지 번호에 사용자 정의 Layer를 선언하여 오브젝트를 분류하는 것이 가능하다.

Layer의 사용 예시는 아래와 같다.
1. 카메라가 어떤 오브젝트만 렌더링하도록 만드는 경우
2. 특정 Layer에 해당하는 오브젝트만 Raycast로 감지하고자 하는 경우
3. 충돌 여부를 Layer 차원으로 조절하여 세밀하게 제어하고자 하는 경우

LayerMask

LayerMask는 특정 Layer만을 대상으로 필터링할 수 있는 비트마스크 값이다.

// Player 레이어의 번호 반환
int playerLayer = LayerMask.NameToLayer("Player");
// 반환된 번호를 기준으로 비트마스크 변환 → Raycast, Physics에서 사용하는 형태
int mask = 1 << playerLayer;

// 내부적으로 Player 레이어를 비트마스크로 변환하여 반환
int targetLayerMask = LayerMask.GetMask("Player");

// Raycast에 LayerMask 활용하는 방법 → boolean값에 영향을 준다.
Physics.Raycast(transform.position, transform.forward, 
out RaycastHit hitInfo, 10f, targetLayerMask)

LayerMask를 인스펙터에 노출시켜 직접 레이어를 선택하는 것 또한 가능하다.

[SerializeField]
private LayerMask targetLayerMask;

Gizmo

실제 게임에서는 구현되지 않는 개발자의 테스트를 위한 도구로, 씬 뷰에서만 보이게 되며 레이캐스트 등 가상의 선을 그려 눈에 보이지 않는 요소를 테스트하는데 사용된다.

기즈모는 2개의 이벤트 함수에서 호출할 수 있다.

private void OnDrawGizmos()
{
	Gizmos.color = Color.Green;
    Gizmos.DrawWireSphere(transform.position, 3f);
}

// 선택해야 보인다.
private void OnDrawGizmosSelected()
{
	Gizmon.color = Color.Red;
	Gizmos.DrawLine(transform.position, transform.forward * 10f);
}

혹은 간편하게 Debug로 호출하는 것도 가능하다.
마찬가지로 씬뷰에서만 보이며, 게임뷰에서는 보이지 않는다.

// 감지된 collider가 있는 경우
// 시작점과 충돌체까지 직선을 초록색으로 그린다
Debug.DrawLine(tansform.position, hitInfo.point, Color.green);

// 감지된 collider가 없는 경우
// 시작점부터 10f 길이의 직선을 빨간색으로 그린다
Debug.DrawLine(transform.position, 
transform.position + transform.forward * 10f, Color.Red); 
profile
뚠뚠뚠뚠

0개의 댓글