본문 바로가기

Unity/▶ Game Development: 2D Game

[2D Game] #4. 스크립트 생성

728x90
반응형

PlayerController 스크립트 생성

PlayerController 스크립트를 생성하여 사용자 입력을 감지하여 점프하고, 충돌을 감지하여 장애물에 닿았을 때 사망 처리를 실행하여 보자. 또한 해당 스크립트를 이용해 상황에 맞는 효과음과 애니메이션을 재생하는 것을 목표로 한다.

 

PlayerController 스크립트를 다음과 같이 작성한다.

using UnityEngine;

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() {}
    private void Update() {}
    
    private void Die() {}
    
    private void OnTriggerEnter2D(Collider2D other){}
    //트리거 콜라이더를 가진 장애물과의 충돌을 감지
    
    private void OnCollisionEnter2D(Collision2D collision){}
    //바닥에 닿았음을 감지하는 처리
    
    private void OnCollisionExit2D(Collision2D collision){}
    //바닥에서 벗어났음을 감지하는 처리
     
}

PlayerController 변수 설명

public AudioClip deathClip; 


public float jumpForce = 700f;
  • deathClip: 사망 시 재생할 오디오 클립(AudioClip) 타입의 변수
  • jumpForce: 점프에서 사용할 힘의 변수
private int jumpCount = 0; 
private bool isGrounded = false; 
private bool isDead = false;
  • jumpCount: 플레이어 캐릭터가 점프한 횟수. 이단/삼단 점프의 구분에 이용됨.
  • isGrounded: 플레이어 캐릭터가 바닥에 닿은 경우 0으로 리셋되는 변수.
  • isDead: 플레이어의 사망 상태 표현하는 변수.
private Rigidbody2D playerRigidbody; 
private Animator animator; 
private AudioSource playerAudio;
  • playerRigidbody: Player 게임 오브젝트의 리지드 바디 2D 컴포넌트 할당
  • animator: Player 게임 오브젝트의 애니메이터 컴포넌트 할당
  • playerAudio: Player 게임 오브젝트의 오디오 소스 컴포넌트 할당

PlayerController Start() 메서드 구현

Start() 메서드에서는 GetComponent() 메서드를 사용하여 Player 게임 오브젝트로부터 사용할 컴포넌트의 참조를 가져와 변수를 할당한다.

private void Start() {
    //게임 오브젝트로부터 사용할 컴포넌트를 가져와 변수에 할당
    playerRigidbody = GetComponent<Rigidbody2D>();
    animator = GetComponent<Animator>();
    playerAudio = GetComponent<AudioSource>();
}

PlayerController Update() 메서드 구현

Update 메서드는 다음과 같은 처리를 실행해야 한다.

  1. 현재 상황에 맞는 애니메이션 재생
  2. 마우스 좌클릭을 감지하고 점프
  3. 마우스 좌클릭을 오래 누르면 높이 점프
  4. 최대 점프 횟수에 도달 시 점프 제한
private void Update() {
    if (isDead)return;
    if (Input.GetMouseButtonDown(0) && jumpCount < 2) {
        jumpCount++;
        playerRigidbody.velocity = Vector2.zero;
        //2차원 벡터의 속도를 (0,0)으로 설정한다.
        playerRigidbody.AddForce(new Vector2(0, jumpForce));
        playerAudio.Play();
    }
    else if (Input.GetMouseButtonUp(0) && playerRigidbody.velocity.y > 0){
        playerRigidbody.velocity = playerRigidbody.velocity * 0.5f;
    }
    animator.SetBool("Grounded", isGrounded);
}
조건 설명 수행
isDead 죽은 경우 이후 처리를 실행하지 않고 바로 종료
Input.GetMouseButtonDown(0)
&& 
(jumpCount < 2)
좌클릭을 실행
&
최대 점프 횟수가
2보다 작은경우
1. 점프 횟수 증가
2. 점프직전의 속도를 (0,0) 으로 변경
3. 위쪽으로 힘 발생: 리지드 바디
4. 오디오 소스 재생
Input.GetMouseButtonUp(0) 
&& 
(playerRigidbody.velocity.y > 0)
좌클릭에서 손을 땐 경우
&
속도의 y값이 양수인 경우
(위로 상승중인 경우)
현재 속도를 절반으로 변경

[ Input.GetMouseButtonDown(0) && (jumpCount < 2) ] 조건을 만족한 경우 점프 직전의 속도를 (0,0)으로 만드는 이유는 직전까지의 힘이 상쇄 혹은 점프 높이의 비일관성을 막기 위함이다.

 

따라서 일반적으로 플랫포머 게임에서 점프를 구현하는 경우 직전 속도에 영향을 받지 않도록 점프 직전 속도를 순간적으로 속도를 제로로 만든다.

animator.SetBool("Grounded", isGrounded);
  • 애니메이터의 Grounded 파라미터를 IsGrounded 값으로 갱신

Set 메서드를 이용하여 Animator 컴포넌트 변수인 animator 변수를 참조하여 애니메이터의 파라미터를 변경한다.

 

애니메이터의 Grounded 파라미터는 Run과 Jump 애니메이션 간 전이의 조건값으로 true인 경우 Run을 실행, flase인 경우 Jump를 실행한다.

Input.GetMouseButton

Input.GetMouseButtonButtonState
//ButtonState: 현재 마우스의 상태
/*
Up: 떼는 순간
Down: 누르는 순간
*/

Input.GetMouseButtonButtonState 메서드는 마우스 버튼 입력을 감지한다. 마우스 입력이 감지되면 true, 아니면 false를 반환한다. 또한 마우스 버튼 식별자int 타입으로 받는다.

0 마우스 왼쪽 버튼(좌클릭)
1 마우스 오른쪽 버튼(우클릭)
2 마우스 휠

이때 마우스 입력을 감지하는 메서드는 3가지 경우가 있다. GetKey 메서드와 비슷하다. GetKey 메서드는 다음을 참고한다.

https://udangtangtang-cording-oldcast1e.tistory.com/50

 

[Dodge] #2. 플레이어

플레이어 스크립트 생성 플레이어를 조종하는 Player Control 스크립트를 생성한다. 하이어라키 > Create > C# Script 생성된 프로젝트의 이름을 Player Control로 변경 게임 오브젝트의 이동을 구현할 때 물

udangtangtang-cording-oldcast1e.tistory.com

Input.GetMouseButton 메서드는 다음과 같다.

Input.GetMouseButton() 마우스 버튼을 누르고 있는 동안
Input.GetMouseButtonUp() 마우스 버튼을 떼는 순간
Input.GetMouseButtonDown() 마우스 버튼을 누르는 순간

즉, Input.GetMouseButtonDown(0)은 마우스 왼쪽 버튼을 누르기 시작한 순간에만 true가 되고, 마우스 왼쪽 버튼을 누르고 있는 동안은 false를 반환한다.

 

다시 강조하자면 Input.GetMouseButton 메서드의 인자는 마우스 버튼 식별자이며, 이는 int 타입으로 0,1,2 중 하나이다.

animator.SetBool

애니메이터 컴포넌트를 나타내는 Animator 타입은 애니메이터의 파라미터 값을 변경할 수 있는 Set 계열의 메서드를 제공한다.

animator.SetBool(string name, bool value)
animator.SetInt(string name, bool value)
animator.SetFloat(string name, bool value)
name 파라미터의 이름
value 해당 파라미터에 할당할 새로운 값

https://udangtangtang-cording-oldcast1e.tistory.com/109?category=1030360 

 

[2D Game] #3. Animator와 transition

애니메이터 컨트롤러와 애니메이터 애니메이터 컨트롤러는 유한 상태 머신을 사용해 재생할 애니메이션을 결정하는 상태도를 표현하는 에셋이다. 애니메이터는 애니메이터 컨트롤러를 참고하

udangtangtang-cording-oldcast1e.tistory.com

이전 포스팅에서는 Run->Jump의 조건을 Grounded 파라미터가 false인 경우, Jump->Run 조건을 파라미터가 true인 경우로 설정했다. 따라서 animator.SetBool("Grounded", isGrounded)에 의해 Run과 Jump 애니메이션이 상황에 따라 전이된다.

PlayerController Die() 메서드 구현

private void Die() {
    animator.SetTrigger("Die");
    
    playerAudio.clip = deathClip;
    playerAudio.Play();
    
    playerRigidbody.velocity = Vector2.zero;
    
    isDead = true;
}

SetTrigger()

animator.SetTrigger("Die");

사망 애니메이션을 재생하기 위해 애니메이터 컴포넌트의 Die 파라미터에 접근한다.

 

이전과 마찬가지로 Animator 타입에 내장된 Set 계열 메서드를 사용한다. SetBool(), SetInt(), SetFloat() 과는 달리 SetTrigger() 메서드는 피라미터의 이름만 입력하고 파라미터에 할당할 새로운 값은 입력하지 않는다.

 

SetTrigger() 메서드는 트리거 타입 파라미터의 방아쇠를 당길 뿐이다. 트리거 타입의 파라미터는 set 하는 즉시 true가 되며 곧바로 false가 되므로 별도의 값을 지정하지 않는다.

 

animate.SetTrigger("Die")가 실행되면 Die 트리거를 조건으로 사용한 Any State->Die 전이가 실행되며, 어떤 상태이든 곧바로 Die 상태로 즉시 전이가 실행된다. 이후 사망 애니메이션을 실행한 다음 플레이어가 죽는 효과음을 재생한다.

playerAudio.clip = deathClip;
playerAudio.Play();

원래 오디오 소스 컴포넌트에 Jump 오디오 클립이 할당되어있었으므로, 죽는 오디오 소스를 실행하기 전에 playerAudio.clip = deathClip;을 실행하여 오디오 소스를 변경한 다음 오디오를 재생한다.

 

playerRigidbody.velocity = Vector2.zero;
isDead = true;

이후 플레이어 캐릭터의 속도를 제로로 설정하고 플레이어 캐릭터의 현재 상태를 사망으로 설정한다.

OnTriggerEnter2D() 메서드

이제 Die() 메서드의 실행조건을 결정해야한다. 우리는 이제 플레이어 캐릭터가 사망하게될 낙사 영역과 장애물 게임 오브젝트에 Dead라는 태그를 할당하고 트리거 콜라이더를 추가할 것이다.

 

따라서 OnTriggerEnter2D() 메서드에서 트리거 충돌을 감지하고 Dead 태그를 가진 오브젝트와 닿았는지 검사하고 Die 메서드를 실행한다. 다만 여기서 2D 콜라이더를 사용하는 경우 OnTriggerEnter()의 2D 버전인 OnTriggerEnter2D()을 사용해야함에 주의한다.

 

트리거 콜라이더는 다음을 참고한다.

https://udangtangtang-cording-oldcast1e.tistory.com/81

 

[Dodge] #4. 탄알 생성

탄알 게임 오브젝트를 생성하고 필요한 컴포넌트를 추가해보자. 탄알은 생성된 후 앞쪽 방향으로 일정 속도로 나아가며, 충돌한 오브젝트가 플레이어면 해당 게임 오브젝트를 파괴한다. 탄알

udangtangtang-cording-oldcast1e.tistory.com

private void OnTriggerEnter2D(Collider2D other) {
    if (other.tag == "Dead" && !isDead)Die();
}
  • 충돌한 상대방 콜라이더의 태그가 Dead이고 isDead의 값이 false인경우(캐릭터가 아직 죽지 않은 경우) Die() 메서드를 실행한다.

OnCollisionEnter2D와 OnCollisionExit2D

isGrounded 변수는 플레이어 캐릭터가 바닥에 닿은 경우 true 바닥에 닿지 않은 경우 false가 된다. 이를 일반 콜라이더와 닿는 순간 true, 일반 콜라이더와 떨어지는 경우 false로 변경하는 방법을 구현한다.

 

따라서 일반 충돌이 시작되는 순간 실행되는 OnCollisionEnter2D() 메서드와 두 콜라이더가 떨어지는 순간 실행되는 OnCollisionExit2D()메서드를 이용한다. 이때 콜라이더 메서드를 2D 버전을 사용해야하는 것을 잊지 않는다.

OnCollisionEnter2D()  일반 충돌이 시작되는 순간 실행
OnCollisionExit2D() 두 콜라이더가 떨어지는 순간 실행
 private void OnCollisionEnter2D(Collision2D collision) {
    if (collision.contacts[0].normal.y > 0.7f){
        isGrounded = true;
        jumpCount = 0;
    }
}

private void OnCollisionExit2D(Collision2D collision) isGrounded = false;

이때 OnCollisionEnter2D()에서 노말 벡터의 방향을 검사했음을 주목한다.

게임 테스트

test1.mov
3.22MB

728x90
반응형
댓글