Unity C# > UnityEngine : Physics
카테고리: UnityDocs
태그: Unity Game Engine
공부하면서 알게된 것만 정리합니다.😀
👩🦰 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계열 함수들의 특성
-
- 유니티에서 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
이런식으로 넘겨야 한다.
- 가상의 구 (SphereCastNonAlloc을 예로 들자면) 가 움직이기도 전에 처음부터 겹쳐있었던 것(
- 게임 속 물체를 클릭한다는 것은 클릭한 화면의 위치로부터, 즉 카메라의 위치로부터 레이저(Raycast)를 쏴서 닿은 물체를 활성화시키는 것과 같다.
- 3인칭 카메라에서 플레이어를 향해 Raycast를 쐈을 때 장애물이 있다면 플레이어를 가리지 않고 제대로 찍을 수 있도록 카메라 위치를 장애물을 넘어가는 곳으로 이동시키는 식으로 구현할 수 도 있다.
- 유니티에서 Collider를 찾아내는 방법은 크게 4 가지가 있다.
✈ 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의 정보가 들어간다.
- if (Physics.Raycast(ray,
- 감지할 레이어 마스크인 다섯번째 인수에
~
을 붙여주면 그 레이어 마스크가 붙은 오브젝트들은 레이 캐스트 처리 하지 말고 무시하라는 뜻.
- Boolean 타입을 리턴한다.
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
에 저장된다.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기