Raycast (레이캐스트)
한 점(origin)에서 특정 방향(direction)으로 보이지 않는 선(Ray)을 쏴서 충돌체(Collider)와의 교차 여부를 검사하는 기능이다.
충돌 지점의 좌표를 이용해 다양한 기능에 활용할 수 있다.
- 총알 및 투사체 명중 판정
- 마우스 클릭으로 오브젝트 선택
- AI의 시야 감지
- 캐릭터 이동 지점 탐지
- 카메라 차폐 처리 (벽 뒤 가림)
기본 구조
Ray ray = new Ray(origin, direction);
if (Physics.Raycast(ray, out RaycastHit hit, 10f))
{
Debug.Log($"충돌한 오브젝트: {hit.collider.name}");
}
- origin: 광선의 시작 위치
- direction: 광선의 방향 (Vector3)
- distance: 광선의 최대 거리
- hit: 충돌 정보를 담는 구조체 (RaycastHit)
RacastHit 구조체
Ray가 충돌한 대상의 정보를 담는 구조체로, 주요 프로퍼티는 다음과 같다.
| collider | 충돌한 Collider |
| point | 충돌 지점의 월드 좌표 |
| normal | 충돌 표면의 법선 벡터 |
| distance | 시작점으로부터의 거리 |
| transform | 충돌한 오브젝트의 Transform |
| rigidbody | 충돌한 Rigidbody (있을 경우) |
예시 : RaycastHit 정보 출력
public class HitInfoExample : MonoBehaviour
{
void Update()
{
if (Physics.Raycast(transform.position, transform.forward, out RaycastHit hit, 100f))
{
Debug.Log("충돌한 오브젝트: " + hit.collider.name);
Debug.Log("거리: " + hit.distance);
Debug.Log("충돌 지점 (월드): " + hit.point);
}
}
}
Raycast 종류 비교
| Physics.Raycast() | 첫 번째로 충돌한 오브젝트 1개만 반환 |
| Physics.RaycastAll() | 광선 경로에 맞은 모든 오브젝트를 배열로 반환 |
| Physics.RaycastNonAlloc() | 미리 할당된 배열에 결과를 저장 (GC 최소화용) |
비교 예제
public class RaycastCompareExample : MonoBehaviour
{
private RaycastHit[] _hitBuffer = new RaycastHit[10];
void Update()
{
Ray ray = new Ray(transform.position, transform.forward);
// A - RaycastAll
if (Input.GetKeyDown(KeyCode.A))
{
RaycastHit[] hits = Physics.RaycastAll(ray, 100f);
Debug.Log($"[All] 감지 개수: {hits.Length}");
foreach (var hit in hits)
Debug.Log($"→ {hit.collider.name} ({hit.distance:F2}m)");
}
// N - RaycastNonAlloc
if (Input.GetKeyDown(KeyCode.N))
{
int count = Physics.RaycastNonAlloc(ray, _hitBuffer, 100f);
Debug.Log($"[NonAlloc] 감지 개수: {count}");
for (int i = 0; i < count; i++)
Debug.Log($"→ {_hitBuffer[i].collider.name} ({_hitBuffer[i].distance:F2}m)");
}
}
}
RaycastAll은 성능 비용이 크고, NonAlloc은 메모리 GC가 거의 없다.
때문에 대량의 감지(탄막, AI 시야 등)에는 nonAlloc을 권장한다.
응용 예시
클릭을 통한 이동 시스템
마우스로 바닥을 클릭하면, 카메라에서 해당 지점으로 Ray를 쏴, 충돌 지점의 월드 좌표를 받아 그 지점으로 캐릭터를 이동시키는 구조다.
이동 로직은 Mesh Agent를 사용했다.
using UnityEngine;
using UnityEngine.AI;
public class ClickToMove : MonoBehaviour
{
public NavMeshAgent agent;
private Camera mainCamera;
void Start() => mainCamera = Camera.main;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, 100f))
{
if (hit.collider.CompareTag("Ground"))
agent.SetDestination(hit.point);
}
}
}
}
카메라 차폐물 처리
플레이어와 카메라 사이에 장애물이 있을때, Raycast를 이용해 카메라 시야를 확보하는 방식이다.
public class CameraOcclusion : MonoBehaviour
{
public Transform player;
public float distance = 5f;
public LayerMask obstacleMask;
void LateUpdate()
{
Vector3 dir = (transform.position - player.position).normalized;
if (Physics.Raycast(player.position, dir, out RaycastHit hit, distance, obstacleMask))
{
transform.position = hit.point - dir * 0.3f; // 살짝 앞당김
}
else
{
transform.position = player.position + dir * distance;
}
transform.LookAt(player);
}
}
자동 사격
플레이어 시야 범위 내의 일정 거리 이내 적이 탐지되면 자동으로 사격한다.
public class AutoShoot : MonoBehaviour
{
public float detectRange = 20f;
public float fireRate = 0.5f;
public LayerMask enemyLayer;
private float _timer;
void Update()
{
_timer += Time.deltaTime;
if (_timer >= fireRate)
{
_timer = 0f;
Ray ray = new Ray(transform.position, transform.forward);
if (Physics.Raycast(ray, out RaycastHit hit, detectRange, enemyLayer))
{
Debug.Log($"적 탐지: {hit.collider.name}");
// 여기서 총알 프리팹 Instantiate() or ParticleSystem Play() 등
}
}
}
}
LayerMask와 Raycast 최적화
Unity의 LayerMask를 사용하면 특정 레이어만 감지하도록 설정해 불필요한 충돌 연산을 피할 수 있다.
int mask = (1 << 8) | (1 << 9); // Layer 8, 9번만 감지
if (Physics.Raycast(ray, out hit, 100f, mask))
{
Debug.Log($"Hit: {hit.collider.name}");
}
내부적으로 LayerMask는 int32 비트 플래그로 구성되어 있어 Unity의 최대 레이어 수는 32개로 제한된다.
비트 or 연산자를 통해 여러 레이어를 포함하는 처리도 가능하다.
'Unity' 카테고리의 다른 글
| Unity - 6000.2.10f1 - InputSystem 버그 (0) | 2025.11.07 |
|---|---|
| Unity 프로젝트 이슈 해결 - 범위내 적 타게팅 최적화 (0) | 2025.11.04 |
| Design Pattern - Observer Pattern (옵저버 패턴) (0) | 2025.10.21 |
| Unity - UGUI : Unity Graphical User Interface (0) | 2025.10.21 |
| Unity - Spawner에 Singleton Pattern 적용하기 (0) | 2025.10.20 |