본문 바로가기
개발/Unity 내일배움캠프 TIL

[내일배움단] Unity TIL 2. 풍선을 지켜라

by 석시 2023. 8. 1.



0. 들어가기에 앞서

앞선 1주차 강의를 마치고, TIL 1편도 정리가 끝났지만, 방법을 수정해야할 필요가 있겠다.

TIL에 모든 내용을 담으려고 하다보니, 배보다 배꼽이 커진느낌.

따라서 앞으로의 TIL은 두 가지를 위주로 정리하려 한다.

  1. Unity 기능과 코드들
  1. 작동 원리에 대해 따로 찾아본 것

Unity와 Visual Studio를 왔다갔다하며 정리하다보니 C#보다 정리하기가 상당히 어렵다.

최대한 핵심 위주로 간결하게 정리해보려 한다.

만들 게임은 다음과 같다.

전 게시글과 비슷한 구성에 마우스 조작과 같은 부분을 추가했다.

구현할 기능들은 다음과 같다.

  1. 기본 씬 구성하기 - 배경, 풍선, 마우스, 네모, 시간
  1. 풍선 애니메이션 더하기
  1. 마우스 움직임 더하기
  1. 시간 가게 하기
  1. 네모 내려오게 하기 + 충돌 구현
  1. 게임 끝내기(1): 판넬 만들기
  1. 게임 끝내기(2): 베스트 스코어 기록하기
  1. 풍선 애니메이션 전환하기

1. 풍선 애니메이션 만들기

저번과 다른 점은 저번은 애셋을 두 개를 써서 애니메이션을 구현했는데, 이번에는 그러한 것 없이 녹화 기능으로 애니메이션을 구현한다.

애니메이션 녹화하기

(Project 탭에서) 녹화하려는 애니메이션을 더블클릭 → 애니메이션 창이 뜨면 (Hierarchy 탭의) 오브젝트를 클릭

녹화버튼이 활성화가 되지 않아 당황할 수도 있는데, 녹화하려는 애니메이션이 담긴 오브젝트를 클릭해줘야 녹화가 가능하니 참고하자.

녹화상태에서 시간초를 이동해 프로퍼티를 변경해주면 다음과 같은 느낌을 완성해낼 수 있다.

2. 마우스에 오브젝트 붙이기

마우스에 오브젝트를 붙여 커서 기능 겸, 물체를 튕겨내는 기능을 마우스가 할 수 있도록 작업해줄 예정이다.

가장 중요한 것은 Screen과 World 사이의 좌표 개념이겠다.

코드) 마우스의 스크린 위치를 게임 좌표로 바꾸기

  • shield.cs 코드
    void Update()
    {
        Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        transform.position = new Vector3(mousePos.x, mousePos.y, 0);
    }

Screen에 게임 세상을 비춰주는건 기본적으로 Camera의 역할이기 때문에 해당 기능 역시 Camera에 탑재되어 있다.

ScreenToWorldPoint()의 자매품으로 WorldToScreenPoint()도 있으므로 참고하자.

3. 버튼 만들기

버튼을 만들 때는 UI 오브젝트에 Button Component를 추가해서 만든다.

Target Graphic

(Inspector 탭에서) Button Component → Target Graphic에 Transition할 Image 오브젝트 드래그

이 때 Target Graphic이라는 것을 설정할 수 있는데 이것은 클릭이 일어날 때 어느 오브젝트가 Color Transition이 일어날 것인가?를 정해준다.

클릭할 때 이펙트를 말하는 것이다.

4. 최고 점수 기능

최고 점수는 씬이 리로딩되거나 게임이 껐다 켜져도 해당 데이터가 유지되어 있어야한다. 이러한 기능 구현은 여러 가지가 있겠지만 가장 간단한 방법으로는 PlayerPrefs가 있겠다.

PlayerPrefs

Playerprefs는 Dictionary 형태로 값을 저장한다.

따라서 다음과 같이 사용할 수 있다.

PlayerPrefs.SetInt("bestScore", value);
PlayerPrefs.SetFloat("bestScore", value);
PlayerPrefs.SetString("bestScore", value);

value = PlayerPrefs.getInt("bestScore");
value = PlayerPrefs.getFloat("bestScore");
value = PlayerPrefs.getString("bestScore");

bool val = PlayerPrefs.HasKey("bestScore")

PlayerPrefs.DeleteAll();

최고점수 기능을 위해선 다음과 같이 구현할 수 있다.

  • gameManager.cs 코드
    public Text bestScoreTxt;
    
    public void gameOver()
    {
        isRunning = false;
        Time.timeScale = 0.0f;
        thisScoreTxt.text = alive.ToString("N2");
        endPanel.SetActive(true);
    
        if (PlayerPrefs.HasKey("bestScore") == false)
        {
            PlayerPrefs.SetFloat("bestScore", alive);
        }
        else
        {
            if (PlayerPrefs.GetFloat("bestScore") < alive)
            {
                PlayerPrefs.SetFloat("bestScore", alive);
            }
        }
    		bestScoreTxt.text = PlayerPrefs.GetFloat("bestScore").ToString("N2");
    }

5. 상태변화 애니메이션

여러 상태나 Parameter에 따라 다양한 애니메이션이 적용되도록 만들 수 있다.

Animator

Project 탭에서 Animation을 생성해서 Object에 드래그를 해서 갖다 놓으면 Project에 파일이 하나 생성되는데, 이것이 Animator이다.

그걸 더블클릭하면 다음과 같은 창을 볼 수 있다.

이곳에서 각 State 별로 어떤 애니메이션이 동작할지 설정해 서있을 때나 걸을 때 등의 모션을 다르게 설정해줄 수 있다.

Transition 추가

(Animator 창에서) 마우스 우클릭 → make transition

편집은 Transition을 클릭하면 Inspector에서 가능하다.

Parameter 추가

(Animator 창에서) Paramaters 탭 → 추가

이후 Transition의 Inspector에서 Conditions로 추가시켜줄 수 있다.

Invoke

Transition을 설정해줘도 실제로 실행해보면 애니메이션이 안나오는 것을 알 수 있다.

Transition으로 State를 넘어가는데는 성공했지만, 시간이 멈춰서 애니메이션 역시 재생이 안되는 것이다.

따라서 예약용 함수인 Invoke()를 사용하여 시간이 멈추는 것을 약간 딜레이시킬 수가 있다.

  • gameManager.cs 코드
    public void gameOver()
    {
        anim.SetBool("isDie", true);
    
        isRunning = false;
        Invoke("timeStop", 0.5f);
        thisScoreTxt.text = alive.ToString("N2");
        endPanel.SetActive(true);
    
        if (PlayerPrefs.HasKey("bestScore") == false)
        {
            PlayerPrefs.SetFloat("bestScore", alive);
        }
        else
        {
            if (PlayerPrefs.GetFloat("bestScore") < alive)
            {
                PlayerPrefs.SetFloat("bestScore", alive);
            }
        }
        bestScoreTxt.text = PlayerPrefs.GetFloat("bestScore").ToString("N2");
    }
    
    void timeStop()
    {
        Time.timeScale = 0.0f;
    }

6. 떨어지는 네모 없애기

교안을 따라 게임을 만들다보면 문제가 하나 있는데, 생성되는 네모들이 없어지지 않다보니 이것들이 점점 쌓이게 된다.

이걸 없애주지 않으면 게임이 매우 느려질 수 있으므로 이를 없애줄 필요가 있다.

  • square.cs 코드
    void Update()
    {
        if (transform.position.y < -7.0f)
        {
            Destroy(gameObject);
        }
    }

하지만 크게 유의해야할 것은 오브젝트를 생성하는 Instatiate()와 오브젝트를 제거하는 Destroy()는 태생 자체가 매우 무거운 함수이기 때문에 너무 자주 호출하게 되면 안된다.

“아니 그러면 어쩌라구요?”

미래에 배울 오브젝트 풀링이라는 것이 있겠다.

시간이 나면 따로 다루도록 하겠다.

끝~


Uploaded by N2T