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광선을 발사하여 충돌된 오브젝트의 정보를 가져오는 기능이다
매개변수로 여러가지 값이 들어갈 수 있다
rayout raycastHit -> 충돌된 오브젝트Mathf.Infinity 무한대
out 매개변수 작동과정
즉, Physics.Raycast()함수가 실행되고, 충돌된 게임 오브젝트에 대한 정보가 raycastHit 변수에 저장된다
-> 이 변수는 충돌한 오브젝트의 정보를 받아오는 역할을 하는 것

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



[SerializeField] 로 선언하였기 때문에, 에디터 내에서 바로 레이어를 설정할 수 있다
LayerMask vs Tag 차이점둘 다 오브젝트를 분류하는 기능을 갖고있지만, 사용 목적이 다르다
레이어는 주로 카메라 컴포넌트에서 렌더링 할 오브젝트를 설정할때도 사용된다

충돌 감지나 레이케스트 최적화 -> 레이어 사용
특정 게임 오브젝트 찾거나 분류-> 태그 사용

마우스 광선과 충돌한 게임 오브젝트의 이름을 반환하기
충돌한 게임 오브젝트의 스크립트를 GetComponent로 가져와서 그 스크립트의 Damage()함수 호출
게임 오브젝트의 체력이 0이 되면 게임 오브젝트 파괴
레이케스트를 사용하기 위해서는 충돌할 오브젝트에 collider가 부착되어 있어야한다
-> 만약 3D 게임 오브젝트를 가져왔을때의 콜라이더 설정
3D 게임 오브젝트의 계층구조에 자식이 붙어있고, 본(뼈)이 따로 설정되어 있는 경우, collider는 본에 붙여줘야한다
-> 이유: 게임 오브젝트의 애니메이션이 실행 될 경우, 부모 계층에 콜라이더를 적용해도 애니메이션을 따라 움직이지 않는다. 반면, 본에 콜라이더를 적용하면 애니메이션을 따라 동일하게 움직인다

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

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

게임 오브젝트의 체력이 0이 되면 게임 오브젝트가 파괴된다
Health 스크립트에는 게임 오브젝트의 체력이 저장되어있다Destroy(gameObject);를 호출하여 파괴된다gameObject는 이 스크립트가 부착된 게임 오브젝트를 의미함!!!
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("게임 오브젝트 파괴");
}
}
}