Development/Unity Engine

[Retro유니티] 2D 충돌구현 - OnTriggerEnter2D / OnCollisionEnter2D / OnCollisionExit2D 오버라이딩

사이바 미도리 2024. 11. 23. 14:14

 

PlayerController 스크립트

- 사용자 입력을 감지하여 Jump

- 충돌을 감지하여 장애물에 닿았다면 Die

- 상황에 맞는 효과음과 애니메이션 재생

 

 

Input.GetMouseButtonDown(0) -> 0은 왼쪽마우스, 1은 오른쪽마우스, 2는 휠클릭이다.

 

Input.GetMouseButtonDown -> 마우스 누르는 순간

Input.GetMouseButton ->마우스 누르는 동안

Input.GetMouseButtonUp ->마우스 떼는 순간

 

우리는 Player 게임 오브젝트의 Audio Source Component에 Jump 오디오 클립을 할당했다.

따라서 그냥 playerAudio.Play(); 하면, 점프 사운드 재생이 된다.

 

 

Die시에는 Die 오디오 클립으로 변경해야한다.

playerAudio.clip = deathClip;
playerAudio.Play(); // 사망효과음 재생

를 하면 된다.

 

OnCollisionEnter2D

유의해야할 부분은 OnCollisionEnter2D인데

   private void OnTriggerEnter2D(Collider2D other) {
       // 트리거 콜라이더를 가진 장애물과의 충돌을 감지
       if(other.tag == "Dead" && !isDead)
         {
            // 충돌한 상대방 태그가 Dead이며, 아직 생존이라면 Die 메서드 실행
            Die();
         }
   }

   private void OnCollisionEnter2D(Collision2D collision) {
       // jumpCount 리셋과 isGrounded 을 결정
       // 바닥에 닿았음을 감지하는 처리
       if(collision.contacts[0].normal.y > 0.7f)
       {
            // Normal Vector의 방향을 검사했음에 유의
              isGrounded = true;
              jumpCount = 0;
       }

   }

   private void OnCollisionExit2D(Collision2D collision) {
       // 바닥에서 벗어났음을 감지하는 처리
       isGrounded = false;
   }
}

OnCollision 계열의 충돌이벤트 메서드는, 여러 충돌정보를 담는 Collision 타입의 데이터를 입력받는다.

- Collision 타입은 충돌지점의 정보를 담는 ContactPoint 타입의 데이터를 contacts 라는 배열변수로 제공한다.

  - contacts 배열의 길이는, 충돌지점의 개수와 일치한다.

 

동일한 방식이 2D 버전인 Collision2D 타입과, ContactPoint2D 에도 그대로 적용된다.

OnCollisionEnter2D에서 사용한 collision.contacts[0]은 두 물체 사이의 여러 충돌 지점 중, 첫 충돌 지점의 정보를 나타낸다.

ContactPoint 와 ContactPoint2D 타입은, 충돌지점에서 충돌표면의 노말벡터를 알려주는 변수인 normal을 제공한다.

 

normal vector의 y값이 1이라면, 표면의 방향은 위쪽이다.

y값이 0이라면 표면의 방향은 완전히 왼쪽 또는 오른쪽이다.

y값이 -1이라면 표면의 방향은 완전히 아래다.

y값이 0.7이라면, 대략 45도의 경사를 가진 채 표면이 위로 향한다는 의미이다.(대충 (-0.7, 0.7) -> 0.49 + 0.49는 대략 1이므로)

y값이 1에 가까워질수록, 경사는 완만해진다.

즉 if(collision.contacts[0].normal.y > 0.7f)

코드가 검사하는 것은

1. 표면의 방향이 위인지

2. 너무 경사가 급한지

이다.

이로써, 절벽이나 천장을 바닥으로 인식하는 문제에서 벗어날 수 있다.

 

PlayerController 전체 코드는 아래와 같다.

using UnityEngine;

// PlayerController는 플레이어 캐릭터로서 Player 게임 오브젝트를 제어한다.
public class PlayerController : MonoBehaviour {
   public AudioClip deathClip; // 사망시 재생할 오디오 클립
   public float jumpForce = 700f; // 점프 힘

   private int jumpCount = 0; // 누적 점프 횟수
   private bool isGrounded = false; // 바닥에 닿았는지 나타냄
   private bool isDead = false; // 사망 상태

   private Rigidbody2D playerRigidbody; // 사용할 리지드바디 컴포넌트
   private Animator animator; // 사용할 애니메이터 컴포넌트
   private AudioSource playerAudio; // 사용할 오디오 소스 컴포넌트

   private void Start() {
       // 초기화
       playerRigidbody = GetComponent<Rigidbody2D>();
       animator = GetComponent<Animator>();
       playerAudio = GetComponent<AudioSource>();
   }

   private void Update() {
       // 사용자 입력을 감지하고 점프하는 처리
       if(isDead) return;
       if(Input.GetMouseButtonDown(0) && jumpCount < 2)
        {
            jumpCount++;
            playerRigidbody.linearVelocity = Vector2.zero; // 현재 속도를 0으로 만들어 점프 직전 상태로 만듦
            playerRigidbody.AddForce(new Vector2(0, jumpForce));
            playerAudio.Play(); // 점프 사운드 재생
        }
       else if(Input.GetMouseButtonUp(0) && playerRigidbody.linearVelocity.y > 0)
       {
           playerRigidbody.linearVelocity = playerRigidbody.linearVelocity * 0.5f;
       }
       animator.SetBool("Grounded", isGrounded);
   }

   private void Die() {
       // 사망 처리
       animator.SetTrigger("Die");
       playerAudio.clip = deathClip;
       playerAudio.Play(); // 사망효과음 재생
       playerRigidbody.linearVelocity = Vector2.zero; // 속도를 제로(0, 0)로 만듦
       isDead = true;
   }

   private void OnTriggerEnter2D(Collider2D other) {
       // 트리거 콜라이더를 가진 장애물과의 충돌을 감지
       if(other.tag == "Dead" && !isDead)
         {
            // 충돌한 상대방 태그가 Dead이며, 아직 생존이라면 Die 메서드 실행
            Die();
         }
   }

   private void OnCollisionEnter2D(Collision2D collision) {
       // jumpCount 리셋과 isGrounded 을 결정
       // 바닥에 닿았음을 감지하는 처리
       if(collision.contacts[0].normal.y > 0.7f)
       {
            // Normal Vector의 방향을 검사했음에 유의
              isGrounded = true;
              jumpCount = 0;
       }

   }

   private void OnCollisionExit2D(Collision2D collision) {
       // 바닥에서 벗어났음을 감지하는 처리
       isGrounded = false;
   }
}

 

이제 DeathClip에 audio를 할당하자. 이걸 위해 public으로 선언했다.

 

동작을 확인가능하다. 현재는 제자리걸음과 이단점프(효과음O, 입력길이로 높이 조절가능)만 하는 상태이다.

정리

1. C# Script에서, Set 계열 메서드로 Animator component 의 Parameter에 값을 할당할수있다.

2. 2D Collider에 대한 충돌 이벤트는, OnTriggerEnter2D / OnCollisionEnter2D / OnCollisionExit2D 함수를 오버라이딩해서 처리할 수 있다.