본문 바로가기
Hello, World!/Unity

유니티 2D 런게임을 만들자(3)

by 27일 낮 2022. 3. 4.
728x90

[ 지난 시간 복습 ]

 

애니메이션 기능을 이용해서 플레이어 오브젝트의 움직임 처리와 같은 비주얼적인 처리를 했음

스크립트뿐 아니라 여러가지를 할 수 있당

 

라이트를 깜빡깜빡거리게 하고 싶다 -> 스크립트로 조절 가능함

라이팅이 가지고 있는 밝기 부분을 시간차에 의해 깜빡깜빡 거리게 조절하면 됨

근데 스크립트가 너무 어렵다면 애니메이션을 쓰면 됨!

시간에 따른 변경 부분을 키프레임으로!

0초에서는 1의 밝기였다면 30초에서는 50%의 밝기 머 이런식으로

1초 동안에 깜빡깜빡~ 계속 재생이 된다

어제 한 것도 마찬가지임!

 

플레이어의 애니메이션 같은 경우도

Run 이라는 애니메이션 클립이,

= 여덟개의 애니메이션 파일이 계속해서 반복될 뿐임

시간차에 의해 일정한 간격으루

계속족으로 반복재생되기 때문에 캐릭터는 계속 걷는 것처럼 보임

어떤 것이든 적용 가능!

 

 

유니티 같은 경우는 애니메이터 컨트롤러에 있는 유한 상태 머신에서......

 

유한 상태 머신은 일정한 상태들의 조건으로 연결성을 부여

점프, 런, 다이 라는 애니메이션 클립이 하나하나의 상태가 되는 거고, 이걸 연결!

 

사용자가 어떤 버튼을 누르거나 했을 때 점프가 했으면 좋겠음! = 다리 중간에 검문소 같은 걸 설치하자

grounded라는 조건을 달아줬음

grounded가 true일 때만 넘어가~~

애니메이터 컨트롤러에서 파라미터 부분에 grounded, die라는 부분으로 설정을 해줬음

연결된 각각의 다리들의 검문소에서 컨디션 부분으로 추가가 가능하다

 

각각의 애니메이션 연결성에서, 

has exit time 이란 건 얼마만큼 애니메이션을 재생해서 넘길거냐? 하는 것

 

내가 걷는 모션이 5초, 점프가 2초짜리라고 치면,

현재 걷고 있는 모션이 재생되는데 1초됐을 때 점프하고 싶은데 has exit time이 체크 되어 있으면

5초의 걷고 있는 모습이 다 끝나고 나서야 점프가 됨

그래서 사용자가 원할 때 모션의 전환이 일어날 수 있도록 체크 해제해주었다

 


이제 스크립트를 작성해보자!

 

 

PlayerController.cs

using System.Collections;
using System.Collections.Generic;
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 AudioSource playerAudio;
    // 사용할 애니메이터 컴포넌트
    private Animator animator;

    void Start()
    ...

전역변수를 먼저 명명했음

그다음은 스크립트에서 사용할 메서드들을 기입해보자!

...
public class PlayerController : MonoBehaviour
{
	...

    void Start()
    {
        // 전역변수의 초기화 진행
    }

    void Update()
    {
        // 사용자의 입력을 감지하고 점프하는 처리
    }

    void Die()
    {
        // 사망 처리
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        // 바닥에 닿자마자 감지하는 처리

    }
    
    private void OnCollisionExit2D(Collision2D collision)
    {
        // 바닥에서 벗어나자마자 처리   
    }
    
    private void OnTriggerEnter2D(Collider2D collision)
    {
        // 트리거 콜라이더를 가진 장애물과의 충돌 감지
    }
}
  • 데드존과 플레이어는 isTrigger가 둘다 체크가 안돼있기 때문에 OnCollision을 써줘야 함
    • 바닥에 닿자마자 - OnCollisionEnter2D
    • 바닥에서 벗어나자마자 - OnCollisionExit2D
  • OnTriggerEnter2D
    • 장애물을 만들건데, 장애물에 닿으면 죽게 할거임!

 

 

    void Start()
    {
        // 전역변수의 초기화 진행
        // 게임 오브젝트로부터 사용할 컴포넌트들을 가져와 변수에 할당
        playerRigidbody = GetComponent<Rigidbody2D>();
        playerAudio = GetComponent<AudioSource>();
        animator = GetComponent<Animator>();
    }
  • GetComponent
    • 메서드임!
      앞에 아무것도 없이 저렇게 GetComponent만 입력해주면,
      지금 PlayerController 스크립트가 Player 오브젝트 안에 들어가있는데
      GetComponent가 실행되면, 이 스크립트가 포함되어있는 오브젝트 내부를 확인
      그럼 그 내부에서 Rigidbody2D를 찾아와서 가지고 오는 게 GetComponent임
      만약 없으면 null 을 반환함. 이건 아무것도 없다는 거~
      나중엔 null 반환할 경우를 대비해 if문도 작성해줄거임 (지금은 안할겨)
// 예시
		playerRigidbody = GetComponent<Rigidbody2D>();
        if (playerRigidbody == null)
        {
            // 예외 처리도 나중에 해줄거임
        }

 

 

 

    void Update()
    {
        // 사용자의 입력을 감지하고 점프하는 처리
        // 1. 현재 상황에 알맞은 애니메이션을 재생
        // 2. 마우스 왼쪽 클릭을 감지하고 점프
        // 3. 마우스 왼쪽 버튼을 오래 누르면 높이 점프
        // 4. 최대 점프 횟수에 도달하면 점프를 못하게 막기

        // 사망 시 더 이상 처리를 진행하지 않고 종료
        if (isDead) return;
    }
  • return이 실행되면 그대로 종료됨
    • update안에 있기 때문에 저 안에 있는 게 계속 실행될건데, isDead가 true가 되는 순간 update문 종료!
    void Update()
    {
        ...
        if (isDead) return;

        // 마우스 왼쪽 버튼을 눌렀으면 & 최대 점프 횟수(2)에 도달하지 않았다면,
        if (Input.GetMouseButtonDown(0) && jumpCount < 2)
        {
        
        }
  • Input.GetMouseButtonDown(0)
    • GetMouseButton : 누르기 시작한 순간부터 뗀 순간까지 전부 다 실행
    • GetMouseButtonDown : 누르는 순간 한번 실행
    • GetMouseButtomUp : 마우스에서 버튼을 뗀 순간 체크

    • 0 : 마우스 왼쪽 버튼
    • 1 : 마우스 오른쪽 버튼
    • 2 : 마우스 휠 버튼

    • 저 키는 모바일에서도 똑같이 작동됨! 스마트폰 탭처럼!
    void Update()
    {
		...

        // 마우스 왼쪽 버튼을 눌렀으면 & 최대 점프 횟수(2)에 도달하지 않았다면,
        if (Input.GetMouseButtonDown(0) && jumpCount < 2)
        {
            // 점프 횟수 증가
            jumpCount++;
            // 점프 직전에 속도를 순간적으로 제로(0,0)으로 변경
            // = 점프 직전까지의 힘 또는 속도가 상쇄되거나 합쳐져서
            //   점프 높이가 비일관적으로 되는 현상을 막기
            playerRigidbody.velocity = Vector2.zero;
            // playerRigidbody.velocity = Vector2(0, 0); 위와 같음!

            // 리지드바디에 위쪽으로 힘 주기
            playerRigidbody.AddForce(new Vector2(0, jumpForce));
        }
    }
  • playerRigidbody.velocity = Vector2.zero;
    • velocity 는 변수
    • Vector2.zero 이거는 함축 표현법!
      • Vector2.zero == Vector2(0, 0)
   void Update()
    {
    		...
            // 리지드바디에 위쪽으로 힘 주기
            playerRigidbody.AddForce(new Vector2(0, jumpForce));

            // 오디오 소스 재생
            playerAudio.Play();
        }
    }
  • playerAudio.Play / Stop / Pause();

 

    void Update()
    {
    ...
			// 오디오 소스 재생
            playerAudio.Play();
        }
        else if(Input.GetMouseButtonUp(0) && playerRigidbody.velocity.y > 0)
        {
            // 마우스 왼쪽 버튼에서 손을 떼는 순간과 속도의 y값이 양수라면(위로 상승 중)
            // 현재 속도를 절반으로 변경
            playerRigidbody.velocity = playerRigidbody.velocity * 0.5f;
        }
	}
  • Input.GetMouseButtonUp(0)
    • 떼는 순간 속도를 줄여버릴거임
  • playerRigidbody.velocity.y > 0
    • 아래로 떨어지고 있는 건 y값이 음수인 상태임! 상승 중이면 양수겠죵
    • 한번 눌렀을 때와 오래 눌렀을 때 점프 속도가 같으면 안되니까 속도를 줄여줘야 함
    • 플레이어가 떨어지는 속도는 일정해야 하니까!
    void Update()
    {
		...
        else if(Input.GetMouseButtonUp(0) && playerRigidbody.velocity.y > 0)
        {
            ...
        }

        // 애니메이터 Grounded 파라미터를 isGrounded 값으로 갱신
        animator.SetBool("Grounded", isGrounded);
    }
  • SetBool
    • 변경해야할 값의 속성으로 적어줘야함!
    • animator.GetBool("Grounded"); 이면, Grounded값을 가져옴!
    void Die()
    {
        // 사망 처리
        // 애니메이터의 Die 트리거 파라미터를 셋
        animator.SetTrigger("Die");

        // 오디오 소스에 할당된 오디오 클립을 deathClip으로 변경
        playerAudio.clip = deathClip;
        // 사망 효과음 재생
        playerAudio.Play();

        // 속도를 제로(0,0)로 변경
        playerRigidbody.velocity = Vector2.zero;

        // 나 사망했어~ 사망 상태를 true로 변경
        isDead = true;
    }
  • animator.SetTrigger("Die");
    • Trigger이기 때문에 Die 이름만 불러주면 끝남
  • playerAudio.clip
    • clip은 AudioSource의 AudioClip을 말함!

  • playerRigidbody.velocity = Vector2.zero;
    • 죽었으니까 속도 x

 

    private void OnCollisionEnter2D(Collision2D collision)
    {
        // 바닥에 닿자마자 감지하는 처리
        // 어떤 콜라이더와 닿았으며, 충돌 표면이 위쪽을 보고 있는지 확인해야함
        if (collision.contacts[0].normal.y > 0.7f)
        {
            // contacts?
            // 충돌 지점들의 정보를 담는 ContactPoint 타입의 데이터를
            // contacts라는 배열 변수로 제공 받음

            // normal : 충돌 지점에서 충돌 표면의 방향(노말벡터)를 알려주는 변수

            // isGrounded를 true로 변경하고, 누적 점프 횟수를 0으로 리셋
            isGrounded = true;
            jumpCount = 0;
        }
    }
  • 어떤 콜라이더와 닿았으며, 충돌 표면이 위쪽을 보고 있는지 확인해야함
    • 왜요?????
      떨어지고 있을 때 점프를 했다고 하자, 근데 이때 ground의 아래에서 점프하다가 ground의 아랫부분과 부딪칠수도 있음!
      이거를 막아야하니, 충돌 표면을 확인하는 것!
  • collision.contacts[0].normal.y > 0.7f
    • collision : 데이터 컨테이너~
    • contacts : 이거는 배열임 
    • 플레이어가 발판에 부딪침! 그럼 이 부딪친 위치에 대한 정보 등 여러가지 정보를 가지고 있음
      왜 배열로 받느냐? 충돌이 여러번 발생될 수 있기 때문에!
      리지드바디는 탄성이라는 걸 가지고 있음(우리는 안썼음) 탄성을 가지고 있으면 (phycis material,,) 충돌 자체가 계에에속 반복됨
    • [0]은 최초 충돌된 정보를 가져오는 것
    • normal : 충돌 지점에서 충돌 표면의 방향(노말벡터)를 알려주는 변수
    • 0.7f : 충돌 표면 기준으로 위쪽을 바라보고 있으면 +1.0, 아래를 바라보고 있으면 -1.0임
      • ground 보면 라운드 되어 있는 부분이 있음 그래서 1.0이 아닌 0.7로 기준을 잡아주었음,,

 

 

...

	private void OnCollisionExit2D(Collision2D collision)
    {
        // 바닥에서 벗어나자마자 처리   

        // 어떤 콜라이더에서 떼어진 경우 isGrounded를 바로 false로 변경
        isGrounded = false;
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        // 트리거 콜라이더를 가진 장애물과의 충돌 감지

        // 충돌한 상대방의 태그가 Dead 이면서, 아직 사망하지 않았다면
        if (collision.tag == "Dead" && !isDead)
        {
            Die();
        }
    }
}

 

 

 

이제 저장하고 유니티로 넘어오자

 

 

Player의 Player Controller Script - DeathClip - Die 노래 넣기

 

 

 

DeadZone - IsTrigger 체크!

와 잘 된다~

댓글