본문 바로가기
공부/Unity

Raycast & LayerMask (쪼까 추가

by Piva 2021. 4. 18.

  뭣도 모르고 쓰는 것좀 그만하자는 취지에서...

 

  상호작용 등에 대해 고민하고 있는데, 상호작용이라고 하면 NPC나 아이템 등 이런 저런 곳과 상호작용할 수 있기 때문에... 상호작용을 하는 범위를 좀 정해놔야 하지 않나 싶었다. 그걸 고민하다 쟤네를 알아보고 좀 써먹어보자 싶어서 알아보기로...

 


Raycast

: Scene에 있는 Collider에 대해서 Ray를 던진다.

(정확히는 Cast a ray란다.)

  • Ray가 Collider와 교차했을 경우 true를 반환, 아니면 false를 반환한다.
public static bool Raycast (Vector3 origin, Vector3 direction, float maxDistance= Mathf.Infinity, int layerMask= DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction= QueryTriggerInteraction.UseGlobal);

 

origin World 좌표계에서 Ray가 시작하는 점.
direction Ray의 방향.
maxDistance Ray가 Collision을 탐색하는 최대 사정 거리.
layerMask 선택적으로 무시할 Collider를 선택하는 데에 사용함.
queryTriggerInteraction 뭔지 모르겠음 나중에 알아봄

 

  • 무시할 Layer를 선택할 수 있기 때문에, 상호작용 같은 행위에 대해선 아이템과 NPC같은 것만 잡히게 처리하면 될듯.

 

RaycastHit

: Raycast에서 반환되는 정보를 받아오기 위해 사용되는 구조체.

이름 설명
barycentricCoordinate 충돌하는 무게중심좌표.
collider 충돌한 Collider.
distance 충돌점과 Ray의 원래 좌표 사이의 거리.
lightmapCoord 충돌점에서의 uv lightmap 좌표계.
normal Ray가 충돌한 표면의 normal(정규 뭐시기 아닐지)
point Ray가 Collider와 충돌한 월드 좌표계 상의 충돌점
rigidbody 충돌한 Collider의 Rigidbody (충돌한 물체에 Rigidbody가 붙어있지 않다면 null이 반환됨.)
transform 충돌한 Collider나 Rigidbody의 Transform 값.

 

Layer(레이어)

  • 주된 사용처

    1. 카메라가 Scene의 일부만 렌더링하도록 함.
    2.
    광원이 Scene의 일부를 비추게 하게 함.
    3.
    Collider를 선별적으로 무시할 수 있게 함.
    4. 충돌(LayerBasedCollision)을 생성하기 위해 사용함.

(이하는 https://docs.unity3d.com/kr/current/Manual/Layers.html의 예시 코드)

 

1. 일부만 렌더링 하게 하기.

  • 카메라에서 Culling Mask를 지정함.
    → 선택한 Layer에 대해서만 렌더링이 이루어짐.
  • UI 및 Canvas의 자식 오브젝트는 카메라의 Culling Mask를 사용하지 않음.

2. Collider의 선별적 무시.

//https://docs.unity3d.com/kr/current/Manual/Layers.html 의 예시 코드
int layerMask = 1 << 8;
        
// Does the ray intersect any objects which are in the player layer.
if (Physics.Raycast(transform.position, Vector3.forward, Mathf.Infinity, layerMask))
{
    Debug.Log("The ray hit the player");
}

// ------------------+--------------------------------------+------------------

void Update ()
{
    // Bit shift the index of the layer (8) to get a bit mask
    int layerMask = 1 << 8;
        
    // This would cast rays only against colliders in layer 8.
    // But instead we want to collide against everything except layer 8. The ~ operator does this, it inverts a bitmask.
    layerMask = ~layerMask;
    
    RaycastHit hit;
    // Does the ray intersect any objects excluding the player layer
    if (Physics.Raycast(transform.position, transform.TransformDirection (Vector3.forward), out hit, Mathf.Infinity, layerMask)) 
    {
        Debug.DrawRay(transform.position, transform.TransformDirection (Vector3.forward) * hit.distance, Color.yellow);
        Debug.Log("Did Hit");
    } 
    else 
    {
        Debug.DrawRay(transform.position, transform.TransformDirection (Vector3.forward) *1000, Color.white);
        Debug.Log("Did not Hit");
    }
}

 

LayerMask

: Physics.Raycast를 사용할 때 Layer 특정에 사용함.

  • Unity에서 GameObject의 Layer는 32개까지 지정할 수 있음.

  • Inspector의 저기에서 적용할 수 있음.
  • 게임 내의 오브젝트의 종류에 따라 지정해놓고 사용하면 될듯.

Project Settings - Physics 2D에서 찾을 수 있는 Layer Collision Matrix

  • 위 사진 속 Matrix에서 무시될 레이어 간의 충돌을 설정할 수 있음. 나 같은 경우, Player와 Item 사이의 충돌을 완전히 무시하게 함.
  • 말그대로 충돌이 완전히 무시되기 때문에 OnCollisonEnter, OnTriggerEnter 같은 것들이 아예 먹히지 않음.

 


 

  아래는 그냥 내가 어떻게 써먹었는지 적어봄.

더보기

  내가 바란 것은 아이템과의 충돌(Collision)이 일어나면 아이템을 획득할 수 있고, 획득한 아이템을 다시금 버릴 수 있게끔 하는 기능이었다. 그런데 아이템을 버리고 습득함에 있어, 아이템이 플레이어의 길목을 막는 방해물처럼 기능하지 않았으면 했음(마치 동물의 숲의 아이템이 플레이어와 충돌하지 않듯이). 그러기 위해 Item과 Player 레이어 사이의 충돌을 아예 무시하도록 했는데, 이렇게 되면 이번엔 아이템의 획득이 불가능해진다. 그렇다고 아이템 자체의 Collider를 없앨 수도 없는게... 지면에 둥둥 떠있는 아이템도 좀 웃기니까... 그래서 야매로 선택한 방법 :

 

  획득 가능한 아이템과 아이템의 Collider(Player와 상호작용이 가능한 범위를 나타내기 위한 용도)를 분리시켜서, 해당 Collider를 아이템의 자식으로 설정한다. Collider에 Player가 들어오면 Player가 상호작용이 가능함을(즉 범위 안에 들어왔음을) 반환하고, 해당 아이템을 획득할 수 있게 하는 것. 이러면 일단 의도한 대로의 기능 구현이 가능했다.

 

(이게 괜찮은 방법인지는 모름 아무튼 의도한게 되었다는게 중요함)

 


잘 거라서 휘갈기고 나중에 채울것

'공부 > Unity' 카테고리의 다른 글

Tilemap (feat. World Building)  (0) 2021.04.09
Unity Animation  (0) 2021.03.22
Input 정리  (0) 2021.03.12