Unity C# > UnityEngine : Physics

Date:     Updated:

카테고리:

태그:

공부하면서 알게된 것만 정리합니다.😀

👩‍🦰 Physics

물리와 관련된 함수들이 미리 들어있는 함수 집합

🚀 변수/프로퍼티

✈ gravity

  • 중력 가속도 상수 벡터
  • Physics.gravity.y 는 y 방향의 중력 가속도를 뜻함.


🚀 함수

✈ OverlapSphere

public static Collider[] OverlapSphere(Vector3 position, float radius, int layerMask = AllLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);

구의 중심 위치(pos)와 반지름을 매개변수로 넘겨주면 구의 반경 내에 있는 모든 * Collider * 들을 Collider 배열로 리턴한다.

  • Physics.OverlapSphere(Vector3 pos, float radius)
    • 추가 매개변수
      • layer도 같이 넘겨주면 해당 layer에 해당하는 Collider들만 들어있는 배열을 리턴한다.


✈ SphereCastNonAlloc

public static int SphereCastNonAlloc(Vector3 origin, float radius, Vector3 direction, RaycastHit[] results, float maxDistance = Mathf.Infinity, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);

이 함수는 인수로 방향과 거리를 넘겨주면 구가 해당 방향과 거리로 이동한 ✨궤적✨에 겹치는 Collider가 있는지를 검사한다. 이게 바로 Cast계열 함수들의 특성

  • image
    • 유니티에서 Collider를 찾아내는 방법은 크게 4 가지가 있다. Ray, Box, Sphere, Capsule 등등 이런 형태의 Collider 컴포넌트를 오브젝트에 달아서 OnTrigger나 OnCollision 같은 이벤트를 사용하여 해당 형태에 겹치는 Collider를 찾아내기도 한다.
    • 그러나 이런 방법의 경우 매 프레임 실행되는 것이기 때문에 순간적으로 딱 한번만 Collider를 찾아내려고 하는 경우에는 성능상 부적절할 수 있다. 매 프레임 실행되므로 적당히 모양을 유지하는 경우에는 사용하기 괜찮지만 그 순간의 겹치는 Collider를 잡아내야 하는 경우에는 힘들기 때문!
    • Physics의 Cast계열 함수 들은 움직이려는 궤적에 충돌하는지를 검사하기 때문에 위와같이 프레임간 사이에서 빠르게 변화하여 감지되지 못할 수 있는 것들도 감지할 수 있도록 해준다.
      • 종류
      • Cast
        • 👉 찾아낸 충돌체 하나만을 구조체로 반환한다. 가장 처음에 충돌한 물체만 반환한다.
      • CastAll
        • 👉 찾아낸 충돌체 전부를 리턴한다. RaycastHit [] 배열로 리턴한다.
      • CastNonAlloc
        • 👉 충돌체들을 리턴이 아닌 인수로 넘긴 RaycastHit 배열에 담아준다. 따라서 CastAll보다는 성능이 더 좋을 수 있다. 다만 찾아낸 충돌체들의 수가 인수로 넘긴 배열의 사이즈보다 적을 수도 많을 수도 있다는 것에 주의하여 사용해야 한다.
        • 직전 프레임까지 어떤 RaycastHit 정보가 있었는지를 알 수 있다.
      • 리턴은 int로 인수로 넘긴 배열이 채워진 사이즈, 즉 충돌체들의 개수를 리턴한다.
    • 움직이려고 하자마자, 즉 궤적을 그리기도 전에 바로 Collider가 걸린 상태라면 첫번째로 감지된 이 Collider의 point는 제로 포인트다.
      • 가상의 구 (SphereCastNonAlloc을 예로 들자면) 가 움직이기도 전에 처음부터 겹쳐있었던 것(hits[0])이 있다면 그 Collider의 point(충돌 위치)는 제로 포인트가 된다.
        • hits[0].point는 (0, 0, 0)
        • 따라서 이런 경우엔 distance도 0 으로 나오게 된다.
      • Collider가 들어있는 것이 아닌 Raycast에 걸린 원소들이 들어 있는 hit 배열의 크기를 리턴한다.
        var size = Physics.SphereCastNonAlloc(attackRoot.position, attackRadius, direction, hits, deltaDistance, whatIsTarget);
        
      • attackRadius 반경을 가진 구가 attackRoot.position에 위치로부터 direction 방향으로 deltaDistance 거리만큼 이동하면서 생긴 궤적(연속선상)에 겹치는 Collider들 중에서 whatIsTarget LayerMask를 가진 Collider가 있다면 그것을 hits 배열에 담고 그 배열의 크기를 리턴한다.
      • out hits 혹은 ref hits 이렇게 레퍼런스로 넘기지 않은 이유는 hits 배열 이름이 그 자체로 레퍼런스가 되기 때문이다. 따라서 그냥 hits로 인수 넘기면 됨.
      • 배열이 아니라 그냥 RaycastHit 자체를 넘기는 것이였으면 value이므로 out hit 이런식으로 넘겨야 한다.
    • 게임 속 물체를 클릭한다는 것은 클릭한 화면의 위치로부터, 즉 카메라의 위치로부터 레이저(Raycast)를 쏴서 닿은 물체를 활성화시키는 것과 같다.
    • 3인칭 카메라에서 플레이어를 향해 Raycast를 쐈을 때 장애물이 있다면 플레이어를 가리지 않고 제대로 찍을 수 있도록 카메라 위치를 장애물을 넘어가는 곳으로 이동시키는 식으로 구현할 수 도 있다.


✈ Raycast

public static bool Raycast(Vector3 origin, Vector3 direction, float maxDistance = Mathf.Infinity, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);

레이캐스트. 눈에 보이지 않는 광선을 쏴서 물리적 충돌을 감지한다.

Boolean 리턴. 물리적인 충돌이 있다면 True 리턴, 없다면 False 리턴.

  • 하나만 부딪치면 끝난다. 하나 충돌되면 더 이상 관통하지 않는다.
    • 관통하고 싶으면 Physics.RaycastAll을 쓰면 된다.
  • Physics.Raycast(발사 위치 Vector3, 발사 방향 Vector3, 광선 길이 float, 감지할 레이어 Layer)
    • 발사 위치로부터 발사 방향으로 float 길이의 광선을 쐈을 때 물리적인 충돌이 감지되면 True 리턴, 없으면 Flase 리턴
    • 발사 위치와 발사 방향은 필수 매개변수다.
  • Physics.Raycast(광선 Ray, 충돌 정보 RaycastHit, 광선길이 float, 감지할 레이어 Layer)
    • Boolean 타입을 리턴한다. Raycast에 걸린게 있다면 true 리턴.
    • Ray는 광선의 발사 위치와 발사 방향을 담고 있는 광선이다.
    • 광선과 충돌한 Collider의 정보를 담는 역할을 하는 RaycastHit 타입의 변수도 매개변수로 넘겨준다. 이때 out을 함께 써서 바로 적용될 수 있게 해주기.
      • if (Physics.Raycast(ray, out hit, distance, whatIsTarget))
        • 광선에 충돌이 감지되는 순간, 이 if 조건문이 실행되자마자 RaycastHit 타입의 hit 변수에 충돌한 Collider의 정보가 들어간다.
    • 감지할 레이어 마스크인 다섯번째 인수에 ~을 붙여주면 그 레이어 마스크가 붙은 오브젝트들은 레이 캐스트 처리 하지 말고 무시하라는 뜻.
Physics.Raycast(transform.position + Vector3.up, Vector3.forward);

광선을 쏠 위치를 설정할 때 이 스크립트의 주인인 오브젝트의 Pivot 위치도 고려해야 한다.! 만약 이 스크립트의 주인이 사람 모양의 오브젝트고 피봇이 발에 있다면 transform.position은 오브젝트의 Pivot을 기준으로 하므로 발에서 Raycast가 나갈 것이다. 따라서 오브젝트의 Pivot 위치를 잘 고려해서 시작 위치를 잡는 것이 좋다. 예시에선 이 스크립트 주인 오브젝트의 Pivot이 발 위치에 있다고 가정할때 Vector.up 즉, (0, 1, 0)만큼만 더 해준 곳에서 Raycast를 쏘게끔 했다.

        if (Input.GetMouseButton(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); 

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

            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 100.0f))
            {
                Debug.Log(hit.collider.gameObject.name);
            }
        }

  Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); 
  • 호출한 카메라 위치로부터 픽셀 단위의 화면상 좌표의 실제 월드 좌표로 향하는 방향의 Ray (광선)을 리턴한다.
    • 아래 과정은 위 함수 한 줄과 비슷하다. 아래 과정에다가 추가로 해당 dir로 향하는 Ray를 직접 리턴한다.
            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;
      
  • 마찬가지로 화면상 좌표(X, Y)와 함께 월드 좌표의 Z 값을 계산할 때 고려할 카메라와의 거리 또한 Z 로 함께 Vector3로 묶어 넘겨 준다.
  • Raycast 에 시작 위치와 방향을 넘기는 대신 광선 자체인 ray를 넘겨준다.


✈ RaycastAll

public static RaycastHit[] RaycastAll(Ray ray, float maxDistance = Mathf.Infinity, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);

    void Update()
    {

        Vector3 look = transform.TransformDirection(Vector3.forward);

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

        foreach (RaycastHit hit in hits)  // 관통되서 광선에 닿은 모든 물체들이 hits 배열에 담긴다. for문으로 모든 원소에 접근
        {
            Debug.Log("Raycast!");
        }
    }

그냥 Raycast는 하나만 충돌되면 더 이상 관통되지 않기 때문에 광선이 관통되게 하고 충돌한 모든 오브젝트를 알고 싶다면 RaycastAll 함수를 써야 한다.

  • Raycast와 다르게 광선에 관통된 모든 오브젝트의 배열을 리턴한다.
            RaycastHit[] hits;
          hits = Physics.RaycastAll(transform.position + Vector3.up, look, 20);
    


✈ Linecast

public static bool Linecast(Vector3 start, Vector3 end, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);

라인캐스트. 눈에 보이지 않는 광선을 쏴서 물리적 충돌을 감지한다.

  • Physics.Raycast(발사시작위치 Vector3, Linecast 종료 지점 Vector3, 충돌 정보 RaycastHit, 감지할 레이어 Layer)
  • Raycast 와의 차이점
    • 👉 Linecast는 정확한 종료 지점을 알 고 어떤 범위 내에서의 충돌을 감지하려 할 때, Raycast는 방향만 알 때 사용!
    • start과 end 사이의 범위내에서 교차하는 충돌이 있을 경우 true를 리턴
    • 충돌 정보는 Raycast hit에 저장된다.




🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

UnityDocs 카테고리 내 다른 글 보러가기

댓글 남기기