Machineboy空

충돌 처리 - RayCast, Collider, Rigidbody, OnCollisionEnter, OnTriggerEnter 본문

Game/Unity

충돌 처리 - RayCast, Collider, Rigidbody, OnCollisionEnter, OnTriggerEnter

안녕도라 2024. 10. 30. 12:38

유니티 물리 엔진은 크게 2D용과 좀 더 복잡한 3D용으로 나뉜다. 물리 엔진은 게임에 생명을 불어넣고, 게임을 좀 더 자연스럽게 만든다. 개발자는 물리 엔진을 사용해 빠르고 쉽게 자연스러운 반응을 하는 새 오브젝트를 추가할 수 있다.

 


충돌 감지 과정에 쓰이는 함수

Ray

Ray ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward);
  • 방향을 가진 빛의 광선
  • 쏘아지는 선이나 직선을 의미하며, 충돌을 테스트하기 위하여 사용

RayCastHit

RaycastHit hitInfo;
bombFX.transform.position = hitInfo.point;
  • ray가 닿은 곳을 의미하며, 충돌에 관련한 정보들을 담고 있다.

Physics.Raycast

RaycastHit hitInfo;

if(Physics.Raycast(ray, out hitInfo, float.MaxValue, layer)){
	GameObject bulletImpact = Instantiate(bulletImpactFactories);
    bulletImpact.transform.position = hitInfo.point;
    bulletImpact.transform.forward = hitInfo.normal;
}
  1. Ray: 터치에 의해 선을 쏜다.
  2. RaycastHit: 충돌 관련한 오브젝트를 레퍼런스한다.
  3. Distance: 충돌 검색을 실행할 최대한의 범위를 의미한다.
  4. Mask: 마스크는 충돌을 체크해야 하는 레이어를 결정한다.
public bool RegisterHitGameObject(PointerEventData data){
	int mask = BuildLayerMask();
    
    Ray ray = Camera.main.ScreenPointToRay(data.position);
    RaycastHit hitInfo;
    
    if(Physics.Raycast(ray, out hitInfo, Mathf.Infinity, mask)){
    	print("Object Hit" +
        hitInfo.collider.gameObject.name);
        
        var go = hitInfo.collider.gameObject;
        HandleHitGameObject(go);
        
        return true;
    }
    
    return false;
}

 

raycast함수는 콜라이더(collider)를 가진 오브젝트와 충돌을 체크한다.

 

*out에 관하여

Call by Reference Call by Value
원본 복사 복사본 복사
사물함에 넣어두고 사물함 번호를 알려주는 방법  
ref, out을 활용  
//01. 보통 함수

int num = 5;

static void ChangeNum(int a)
{
		a = 10;
}

ChangeNum(num);
ConSole.WriteLine(num);

// num = 5; <<값이 변경되지 않았다.
// 이유: 함수 바깥 scope != 함수 내 scope 다른 공간으로 인식

 

//02. ref 이용 함수

int num = 5; // 5를 할당해주지 않으면 문제가 생긴다.

static void RefNum(ref int a)
{
		a=10;
}

RefNum(ref num);
Console.WriteLine(num);

// num = 10;
// ref 사용하여 함수 내 scope에 접근
//03. out 이용 함수

int num =5; // 5를 굳이 할당해줄 필요가 없다!

static void OutNum(out int num)
{
		num = 10;
}

OutNum(out num);
Console.WriteLine(Num);

// num = 10;
// out 이용하여 함수 내에서 함수 외부 scope로 접근

 

https://yeko90.tistory.com/entry/c-%EA%B8%B0%EC%B4%88-ref-vs-out-%EC%B0%A8%EC%9D%B4

 

[c# 기초] ref vs out 차이

이번 포스팅에서는 비슷한듯 다르게 보이는 ref와 out차이를 알아보도록 하겠습니다. 그 전에 이를 제대로 이해하기 위해선 ref를 이용한 함수와 이용하지 않은 보통 함수에 대한 이해가 선행 되

yeko90.tistory.com

 


충돌 감지를 위해 필요한 컴포넌트

오브젝트의 물리를 판단하기 위해 리지드바디와 콜라이더 컴포넌트는 꼭 필요하다. 다음은 각 컴포넌트가 무엇을 담당하고 서로 어떻게 연관돼 있는지 간략히 요약한 내용이다.

RigidBody

  • 오브젝트의 질량과 관련된 속성을 정의한다고 이해하면 된다.
  • 중력에 반응하는지, 질량은 얼마인지, 얼마나 쉽게 회전하는지

Collider

  • 일반적으로 오브젝트의 경계를 정의하는 단순한 도형이다.
  • 빠르게 충돌을 감지하기 위해 박스, 구체, 캡슐과 같은 단순한 도형이 사용된다.
  • 좀 더 복잡한 메시(mesh) 혹은 실제 캐릭터 메시와 같이 복잡한 형태를 사용하는 경우 충돌을 체크할 때마다 물리 엔진이 부하를 줘서 멈춰버릴 수도 있다.
  • 물리 엔진은 매 프레임마다 오브젝트들이 서로 충돌했는지를 체크한다.
  • 오브젝트들끼리 충돌한 경우에는 뉴턴의 운동 법칙을 사용해서 충돌의 영향을 판단한다.
  • 좀 더 복잡한 게임의 경우 몸통과 신체 여러 부분에 여러 개의 캡슐 콜라이더를 사용하여, 각 신체 부분에 대한 충돌을 감지하기도 한다.

충돌 체크

유니티 물리 엔진에 오브젝트끼리 충돌할 때 사용할 수 있는 기본 메소드들

OnCollisionEnter

  • 오브젝트에 콜라이더가 있고, 콜라이더를 가진 또 다른 오브젝트와 충돌하는 경우
  • 두 오브젝트는 접촉한 후, 한 개나 두 개의 오브젝트 모두 리지드바디를 가지고 있으면 충돌의 힘에 따라 서로를 밀어낸다.
  • 충돌을 위해 리지드바디가 필요하지 않지만 콜라이더는 필요하다.

OnTriggerEnter

  • 오브젝트에 콜라이더가 있지만 콜라이더가 트리거로 설정돼 있는 경우
  • 트리거로 설정돼 있는 콜라이더는 충돌을 감지하지만 두 오브젝트가 서로 지나치게 한다.
  • 문이나 포털처럼 오브젝트가 들어오는 순간을 감지하고 싶을 때 유용하다.

충돌 오브젝트간 스크립트 구성 팁

  • CollisionAction
    • 다른 오브젝트와 부딪히는 볼이나 총알같은 오브젝트에 첨부한다.
    • 스크립트는 충돌을 감지하고 CollisionReaction을 가진 오브젝트에 충돌을 알려준다.
  • CollisionReaction
    • 오브젝트와 충돌할 떄 일어나는 여러 가지 일들을 처리한다.
//CollisionAction

void OnCollisionEnter(Collision collision){
	if(disarmed == false){
    	reactions = collision.gameObject.GetComponents<CollisionReaction>();
        
        if(reactions != null && reactions.Length() >0){
        	foreach(var reaction in reactions){
            	if(gameObject.name.StartWith(reaction.collisionObjectName)){
                	reaction.OnCollisionReaction(gameObject, collision);
                }
            }
        }
    }
}
//CollisionReaction

public void OnCollisionReaction(GameObject go, Collision collision){
	ContactPoint contact = collision.contacts[0];
    Quaternion rot = Quaternion.FromToRatation(Vector3.up, contact.normal);
    
    Vector3 pos = contact.point;
    
    if(particlePrefab != null){
    	var particle = (Transform)Instantiate(particlePrefab, pos, rot);
        Destroy(particle.gameObject, destroyParticleDelaySeconds);
    }
    
    if(destroyObject){
    	Destroy(go, destroyObjectDelaySeconds);
    }
    
    collisionEvent.Invoke(gameObject, collision);
}