반응형

1. RayCasting

rpg 게임에서 말 그대로 Object 를 클릭한다면 원하는 Object 에서 클릭 이벤트가 발생해야 한다. 즉 레이저를 쏴서 해당 레이저에 존재하는 Object 를 클릭하기 위함이다. 또는 케릭터의 정면에 레이저가 발사되어 일정 범위 내에 유닛만 타격하는 범위를 지정한다던지 다양하게 응용될 수 있는 기술이다. 즉 광선과 객체의 교차점을 파악하는 기술

Vector3 look = transform.TransformDirection(Vector3.forward);
Debug.DrawRay(transform.position + Vector3.up, look * 10, Color.red);

RaycastHit hit;

if (Physics.Raycast(transform.position + Vector3.up, look, out hit, 10))
   Debug.Log($"RayCast @ {hit.collider.gameObject.name} !");

RaycastHit[] hits;
hits = Physics.RaycastAll(transform.position + Vector3.up, look, 10);

foreach (RaycastHit hitt in hits)
{
   Debug.Log($"RayCastAll @ {hitt.collider.gameObject.name} !");
}

Update() 문에서 위의 코드를 작성하여 케릭터가 응시하는 곳에 레이저를 발사하여 그 위치에 존재하는 객체에 대해 Console 로그를 출력하는 코드이다.

look 변수에는 TransformDirection 을 통해 PlayerObject 가 바라보는 방향 벡터를 가지게 된다.
그리고 DrawRay 를 사용하면 Unity 엔진에서 테스트를 실행했을 때 광선을 그려주게 된다.
기본적으로 transform.position 을 사용하면 PlayerObject의 발끝이 기준점이기 때문에 바닥에 레이저가 그려지게 되어 Vector3.up 을 더해준다. 그리고 look 방향 벡터에 10의 크기를 가지게하고 red 색상을 지니게 하면 아래와 같이 레이저를 확인할 수 있다.

해당 광선과 Object 의 교차점이 생겼을 때 특정 이벤트를 발생시키기 위해 위 코드상에서 Physics.Raycast 를 사용해준다.

RaycastHit hit;

if (Physics.Raycast(transform.position + Vector3.up, look, out hit, 10))
   Debug.Log($"RayCast @ {hit.collider.gameObject.name} !");

DrawRay 가 그려준 Ray 와 동일하게 Raycast 를 했을 때 만약 out hit 로 교차점이 생긴 객체가 있다면 해당 객체 name 을 출력해준다.

RaycastHit[] hits;
hits = Physics.RaycastAll(transform.position + Vector3.up, look, 10);

foreach (RaycastHit hitt in hits)
{
   Debug.Log($"RayCastAll @ {hitt.collider.gameObject.name} !");
}

혹은 Raycast 범위에 투영되어 많은 객체가 선택된다면 RaycastAll 함수를 사용하여 foreach 로 모두 출력해줄 수 있다.

 

2. Camera Raycasting

위 코드는 PlayerObject 를 기준으로 Raycasting 이 되었기 때문에 케릭터의 정면에 Ray 가 생성되었다.
하지만 보통의 rpg 게임에선 유저가 특정 객체를 클릭하기 위해 마우스를 선택하고, Ray 가 발생되는 기준이 카메라일 필요가 있다.

if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            //Vector3 mousePos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane));
            //Vector3 dir = mousePos - Camera.main.transform.position;
            //dir = dir.normalized;
            // same ray

            Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.red, 1.0f);
            // Debug.DrawRay(Camera.main.transform.position, dir * 100.0f, Color.red, 1.0f);

            RaycastHit hit;

            LayerMask mask = LayerMask.GetMask("Monster") | LayerMask.GetMask("Wall");
            //int mask = (1 << 8) | (1 << 9);

            if (Physics.Raycast(ray, out hit, 100.0f, mask))
            // if (Physics.Raycast(Camera.main.transform.position, dir, out hit, 100.0f))
            {
                Debug.Log($"Raycast Camera @ {hit.collider.gameObject.name}");
            }
        }

GetMouseButtonDown(0) 으로 마우스 클릭 이벤트가 발생했을 때 해당 이벤트가 실행되는데,

Vector3 mousePos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane));
Vector3 dir = mousePos - Camera.main.transform.position;
dir = dir.normalized;

ScreenToWorldPoint 를 통해 마우스가 클릭한 지점의 좌표를 가져온다. 그리고 카메라의 position 값을 빼면 방향 * 거리를 가진 벡터가 계산되는데 normalized 를 통해 방향 벡터로 만들어준다. 즉 카메라에서 클릭한 지점의 방향 벡터를 구하는 코드이다.
이와 같이 자주 사용되는 코드는 아래와 동일하게 사용할 수 있다.

Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

Ray 타입의 변수에 ScreenPointToRay 함수를 사용하면 클릭한 마우스의 방향 벡터를 쉽게 반환해준다.
마찬가지로 클릭한 지점에 대해 정확한 좌표를 구하는지 DrayRay 를 통해 확인하고 싶다면 아래와 같이 작성해준다.

Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.red, 1.0f);

빨간색 Ray 를 그려주는데, 시작점은 main Camera 이며 ray.direction 으로 방향에 100을 곱해주어 거리를 늘려준다.
그리고 이 레이저는 1초 뒤 사라지도록 작성해준다.

현재 클릭을 감지할 Object 의 Layer 에는 8, 9 번 Layer에 지정해두었기 때문에 해당 Layer 만 감지하도록 아래와 같이 작성한다.

LayerMask mask = LayerMask.GetMask("Monster") | LayerMask.GetMask("Wall");
            //int mask = (1 << 8) | (1 << 9);

            if (Physics.Raycast(ray, out hit, 100.0f, mask))
            // if (Physics.Raycast(Camera.main.transform.position, dir, out hit, 100.0f))
            {
                Debug.Log($"Raycast Camera @ {hit.collider.gameObject.name}");
            }

이렇게 하면 Raycast 가 ray 방향으로 100의 거리만큼 cast 했을 때 mask 에 해당하는 object 가 있다면 hit을 반환하고 이 hit 객체의 name 을 출력하도록 작성해주면 테스트가 가능하다.

이런식으로 클릭 시 Raycast 가 되며, 해당 cast 된 위치에 Object 가 있다면 이름을 출력해주게 된다.

반응형