Unity Term Book
물리

Raycasting

Raycasting은 방향으로 보이지 않는 광선을 쏴 Collider를 찾습니다. 사격·지면 검사·마우스 피킹·시야의 기초이며 LayerMask·maxDistance·SphereCast까지 다룹니다. 성능과 정확도를 함께 잡는 Unity 레이캐스트의 실전 가이드입니다.

상상해 보세요...

Raycast는 어둠 속의 손전등과 같습니다. 한 방향으로 비추면 빔이 무언가에 닿을 때까지 갑니다. 그다음 무엇을 맞췄는지, 얼마나 멀리, 어디, 그리고 이 어느 쪽인지 보고합니다. 슈터에서는 실제 물리 총알 대신 — 더 싸고 빠르고 정밀합니다.

개념 자세히

Physics.Raycast()는 origin·direction을 받아 Collider에 맞으면 true를 반환합니다. 상세는 RaycastHit에: 히트 위치( .point), 면 방향(.normal), 거리( .distance), 오브젝트(.collider).

Unity는 여러 변형을 제공합니다: Physics.RaycastAll()은 경로상 모든 Collider(최근접만이 아님), Physics.SphereCast()는 구를 쓸어(캐릭터 “스냅”이 부드러움), Physics.BoxCast()는 상자를 쓸어갑니다. Unity 2022+부터 Physics.RaycastCommand로 Job System에서 병렬 raycast도 가능합니다.

성능: Raycast는 공짜가 아닙니다 — 호출마다 broadphase BVH를 걷습니다. 항상 LayerMaskmaxDistance를 넘기세요. 매 프레임 루프는 피하세요 — AI는 매 프레임 대신 0.2초마다 4방향 raycast.

흔한 용도: shooting(hitscan, Rigidbody 총알 없음), ground check(점프 전 지면 확인), mouse picking( Camera.ScreenPointToRay()로 클릭을 3D ray로), line of sight(AI와 플레이어 사이 장애물).

Raycast 변형

Raycast

직선 레이. 반환값은 가장 가까운 Collider. 거의 모든 용도에 사용.

Physics.Raycast()

SphereCast

구형 스윕 — 캐릭터, 대형 무기, 넓은 범위 감지에 적합.

Physics.SphereCast()

RaycastAll

경로상의 모든 Collider를 반환. 철갑탄, 유리를 통과하는 빛에 사용.

Physics.RaycastAll()

실습 단계

1

origin과 direction 정하기

FPS는 종종 Camera.main.transform.position과 .forward, 지면 검사는 Vector3.down.

2

RaycastHit 선언

RaycastHit hit; — Physics.Raycast()에 out hit로 넘깁니다. GC를 피하려면 Update 밖에 둡니다.

3

LayerMask 설정

Inspector에서 할당하거나 LayerMask.GetMask("Enemy", "Ground")로 필요한 것만 검사합니다.

4

maxDistance 제한

항상 최대 거리를 넘기세요 — 무한 ray는 씬 전체를 검사합니다. 예: 총 사거리 50f, 지면 검사 1.2f.

5

Scene view에 Debug Ray

Debug.DrawRay(origin, direction * maxDist, Color.green) — 플레이 중만 보이고 빌드에는 영향 없음.

인터랙티브 시뮬레이터

캔버스 위에서 마우스를 움직여 ray를 조준하세요. 장애물을 드래그할 수 있습니다.

마우스를 움직이세요...

아직 히트 없음

코드 예제

기본

Hitscan 사격 — Rigidbody 총알 없이 발사.

using UnityEngine;

public class HitscanGun : MonoBehaviour
{
  public float range = 50f;
  public int damage = 25;
  public LayerMask shootMask;
  public ParticleSystem muzzleFlash;

  Camera cam;
  RaycastHit hit; // Declare outside Update to avoid GC

  void Start() => cam = Camera.main;

  void Update()
  {
      if (Input.GetButtonDown("Fire1")) Fire();
  }

  void Fire()
  {
      muzzleFlash.Play();

      // Ray from camera center, forward
      if (Physics.Raycast(cam.transform.position,
                         cam.transform.forward,
                         out hit, range, shootMask))
      {
          Debug.Log("Hit: " + hit.collider.name +
                     " at " + hit.distance.ToString("F1") + "m");

          hit.collider.GetComponent<Health>()
             ?.TakeDamage(damage);
      }
  }
}

코드 예제

고급

정확한 지면 검사 + 마우스→월드 피킹 — 가장 흔한 두 용도.

using UnityEngine;

public class RaycastUtils : MonoBehaviour
{
  [Header("Ground Check")]
  public float groundCheckDist = 1.2f;
  public LayerMask groundLayer;
  bool isGrounded;

  [Header("Mouse Picking")]
  public LayerMask clickable;

  Camera cam;
  RaycastHit hit;

  void Awake() => cam = Camera.main;

  void Update()
  {
      // Ground check every frame — SphereCast is smoother than Raycast
      isGrounded = Physics.SphereCast(
          transform.position, 0.4f,
          Vector3.down, out hit,
          groundCheckDist, groundLayer
      );

      // Click → world position
      if (Input.GetMouseButtonDown(0))
      {
          Ray ray = cam.ScreenPointToRay(Input.mousePosition);
          if (Physics.Raycast(ray, out hit, 100f, clickable))
          {
              Debug.Log("Clicked: " + hit.collider.name);
              // Move the character to hit.point
              MoveTo(hit.point);
          }
      }
  }

  void OnDrawGizmosSelected()
  {
      Gizmos.color = isGrounded ? Color.green : Color.red;
      Gizmos.DrawLine(transform.position,
          transform.position + Vector3.down * groundCheckDist);
  }
}

📌 빠른 정리

  • 항상 LayerMask + maxDistance 전달
  • RaycastHit는 Update 밖에 한 번 선언(GC 방지)
  • 마우스→3D는 Camera.ScreenPointToRay()
  • Scene view에서 Debug.DrawRay()
  • 캐릭터 이동은 SphereCast가 Raycast보다 부드러움

⚠️ 흔한 실수

  • ❌ ray가 자기 자신을 맞춤(self-hit)

    origin이 사수 Collider 안 — 항상 true

    ✅ origin을 forward로 +0.1f 오프셋, 또는 자기 Layer 무시

  • ❌ MaxDistance 없이 매 프레임 Raycast

    무한 ray가 씬 전체를 검사해 FPS 하락

    ✅ 용도에 맞는 maxDistance를 항상 전달