[Unity] 10. Raycast

치치·2025년 2월 27일
0

Unity

목록 보기
12/27
post-thumbnail

Ray (광선)

  • 광선(Ray)을 발사하여 충돌체를 감지하고, 그 충돌한 물체와의 정보를 얻을 수 있게 해주는 기능이다

  • Raycast는 광선을 지정된 방향으로 쏴서 그 광선이 다른 collider와 충돌하는 지 확인하는 방식이다

  • 광선을 발사했는데, 상대 오브젝트의 collider가 없으면 충돌되지 않는다

  • Ray는 출발점(origin)과 방향(direction)을 가지고 있다


화면에 마우스 입력받기

  • 마우스의 입력은 기본적으로 2D 스크린 공간에서 발생하고, 3D 게임 오브젝트는 월드 공간에 존재하기 때문에 마우스로 화면을 클릭해도 3D 오브젝트와 바로 상호작용할 수 없다

  • Raycast를 사용하여 2D 공간에서 3D 공간으로 공간 변환을 해주자

  • ray = Camera.main.ScreenPointToRay(Input.mousePosition); : 2D 스크린 좌표를 기준으로 3D 공간에 Ray를 쏘는 데 필요한 Ray 객체를 만든다

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Picking : MonoBehaviour
{
    [SerializeField] Ray ray; // 광선에 대한 정보 

    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            // 카메라 오브젝트를 다이렉트로 넣을 수 있는 코드 (Camera.main == 메인 카메라를 의미)
            ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            Debug.Log("ray.direction : " + ray.direction);
            Debug.Log("ray.origin : " + ray.origin); //  
        }
    }
}

Raycast & RaycastHit

광선을 발사하여 충돌된 오브젝트의 정보를 가져오는 기능이다

함수 원형

매개변수로 여러가지 값이 들어갈 수 있다

  1. 발사하는 광선 ray
  2. 출력용 매개변수 out raycastHit -> 충돌된 오브젝트
  3. 광선 거리 Mathf.Infinity 무한대
  4. 충돌할 레이어 설정


out 매개변수 작동과정


즉, Physics.Raycast()함수가 실행되고, 충돌된 게임 오브젝트에 대한 정보가 raycastHit 변수에 저장된다
-> 이 변수는 충돌한 오브젝트의 정보를 받아오는 역할을 하는 것

이렇게 레이케스트를 사용하면 충돌된 오브젝트에 대한 정보를 얻을 수 있다


LayerMask

레이케스트를 사용할때, 특정 레이어에 속한 오브젝트만 감지하도록 제한하는 역할
-> 원하지 않는 오브젝트는 무시할 수 있게 설정할 수 있다

  • 인스펙터 창에서 레이어를 추가하여 사용할 수 있다

  • [SerializeField] 로 선언하였기 때문에, 에디터 내에서 바로 레이어를 설정할 수 있다

LayerMask vs Tag 차이점

  • 둘 다 오브젝트를 분류하는 기능을 갖고있지만, 사용 목적이 다르다

  • 레이어는 주로 카메라 컴포넌트에서 렌더링 할 오브젝트를 설정할때도 사용된다

  • 충돌 감지나 레이케스트 최적화 -> 레이어 사용

  • 특정 게임 오브젝트 찾거나 분류-> 태그 사용



레이케스트 실전 사용 (데미지 입히기)

  • 마우스 광선과 충돌한 게임 오브젝트의 이름을 반환하기

  • 충돌한 게임 오브젝트의 스크립트를 GetComponent로 가져와서 그 스크립트의 Damage()함수 호출

  • 게임 오브젝트의 체력이 0이 되면 게임 오브젝트 파괴



게임 오브젝트 설정

  • 레이케스트를 사용하기 위해서는 충돌할 오브젝트에 collider가 부착되어 있어야한다
    -> 만약 3D 게임 오브젝트를 가져왔을때의 콜라이더 설정

  • 3D 게임 오브젝트의 계층구조에 자식이 붙어있고, 본(뼈)이 따로 설정되어 있는 경우, collider는 본에 붙여줘야한다
    -> 이유: 게임 오브젝트의 애니메이션이 실행 될 경우, 부모 계층에 콜라이더를 적용해도 애니메이션을 따라 움직이지 않는다. 반면, 본에 콜라이더를 적용하면 애니메이션을 따라 동일하게 움직인다

  1. 레이케스트를 이용해서 충돌된 게임 오브젝트의 콜라이더에 접근하여 오브젝트 이름을 알아낼 수 있다
    -> 콜라이더가 부착되있는 곳은 자식이기 때문에, 부모 오브젝트의 이름을 알려면 transform.root

  2. 충돌된 게임 오브젝트의 정보를 갖고있는 raycastHit를 참조해,GetComponent로 스크립트를 가져와서 Damage()함수를 호출할 수 있다
    -> 스크립트가 부착되어 있는 곳은 게임 오브젝트의 부모쪽 <<<
    -> 접근할때도 transform.root로 부모쪽의 Health 스크립트를 가져와야한다

  3. 게임 오브젝트의 체력이 0이 되면 게임 오브젝트가 파괴된다

  • 게임 오브젝트에 붙어있는 Health 스크립트에는 게임 오브젝트의 체력이 저장되어있다
  • Damage() 함수는 매개변수로 들어온 값이 현재 체력에 반영이 되게 작성되어있다
  • 만약 체력이 0 이하일 경우 Destroy(gameObject);를 호출하여 파괴된다
    -> ✅ gameObject는 이 스크립트가 부착된 게임 오브젝트를 의미함!!!

Picking & Health 전체 코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Picking : MonoBehaviour
{
    [SerializeField] Ray ray; // 광선에 대한 정보 
    [SerializeField] RaycastHit raycastHit;

    [SerializeField] private float attack;

    [SerializeField] LayerMask layerMask;

    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            // 카메라 오브젝트를 다이렉트로 넣을 수 있는 코드 (Camera.main == 메인 카메라를 의미)
            ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            // 발사할 레이, 출력용 매개변수로 값이 들어옴
            if(Physics.Raycast(ray, out raycastHit, Mathf.Infinity, layerMask))
            {
                Debug.Log(raycastHit.collider.transform.root.name);

                // 스크립트가 존재하는 부모쪽에서 겟 컴포넌트 (콜라이더는 자식에 있지만)
                raycastHit.collider.transform.root.GetComponent<Health>().Damage(attack);
            }
        }
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Health : MonoBehaviour
{
    [SerializeField] private float health;

    private void Start()
    {
        health = 100f;
    }

    public void Damage(float damage)
    {
        health -= damage;
        Debug.Log("현재 체력 : " + health);
        if(health <= 0)
        {
            Destroy(gameObject);
            Debug.Log("게임 오브젝트 파괴");
        }
    }
}

profile
뉴비 개발자

0개의 댓글