티스토리 뷰

반응형

 

오늘도 저번 포스트에 이어서 Flappy Bird 게임을 만들어보겠습니다! 많은 의견 주세용😁~

앞 포스트를 못보셨으면 링크 참고해주세요!

GitHub 코드와 APK파일은 마지막 글에 있습니다.

 

 

2020/03/11 - [Unity 게임 개발] - [Unity 게임 개발 고수 되기 #1. Flappy Bird ] 02. 기둥과 점수존 스폰/비활성화, 게임 오버, 점수 획득, UI 구현하기

 

[Unity 게임 개발 고수 되기 #1. Flappy Bird ] 02. 기둥과 점수존 스폰/비활성화, 게임 오버, 점수 획득, UI 구현하기

Flappy Bird 두 번째 포스트입니다! 아직 초보 개발자이니 부족한 부분은 의견 주시면 감사하겠습니당😊😊 그전에 첫번째 포스트를 못보신 분은 아래 링크 참고해 주세요! 2020/03/11 - [Unity 게임 개발] - [Unit..

codingwell.tistory.com

 

 

2020/03/11 - [Unity 게임 개발] - [Unity 게임 개발 고수 되기 #1. Flappy Bird ] 01. 플레이어와 바닥 움직임,기둥과 점수존의 오브젝트 풀링 구현

 

[Unity 게임 개발 고수 되기 #1. Flappy Bird ] 01. 플레이어와 바닥 움직임,기둥과 점수존의 오브젝트 풀링 구현

Unity로 예전에 인기가 많았던 모바일 게임 Flappy Bird를 처음부터 끝까지 혼자 개발해보려고 해요! 다들 해보셨던 기억이 있나요? 화면을 터치하면 새가 점프하고 기둥이나 바닥에 부딪히지 않고 기둥 사이를 잘..

codingwell.tistory.com

 

 

 

 

 

유니티로 구현하기

 

1. Game Over 시 애니메이션과 UI 구현하기

 

플레이어가 기둥이나 바닥에 부딪히는 당시에 화면이 번쩍하면서 스파클이 튀는 것 같은 애니메이션이 실행됩니다.

저는 이 애니메이션을 실행하기 위해서 Canvas 에 Animator를 만들었습니다.

 

니메이션은 저번 포스트에서 설명했던 방법과 비슷하게 (r,g,b,a)를 (1,1,1,1)   0.2초-->   (1,1,1,0) 로 했습니다.

불투명하게 하얀 화면이 보였다가 빠르게 투명해지는 애니메이션입니다.

 

Animator 창에서 파라미터로 Trigger를 하나 만듭니다. Any State -> GameOver 화살표를 누른 후 Inspector 창의 Conditions에서 추가했던 Trigger를 설정합니다.

스크립트 수정은 UI 까지 만든 후에 하겠습니다.

 

 

 

 

 

 

 

플레이어가 기둥이나 바닥에 부딪혀 게임오버가 되면 다음과 같은 UI가 나타납니다.

 

GameOver UI

① Game Over 글자 (Image)

② Panel (Image) - 메달 (Image), Final Score (Text), Best Score (Text), New Score(Image)

③ Start 버튼 (Button)

④ 랭킹 버튼 (Button)

 

 

참고로 Panel의 New Score (Image) 는 최고 점수 기록을 깼을 경우에만, 

BEST 옆에 New라는 이미지가 뜨게끔 할 것 입니다.

 

 

 

 

 

 

 

 

Hierarchy의 Canvas안에 빨간 네모박스 처럼 추가해주시면 됩니다.

빈 오브젝트 GameOver UI를 만들고 자식으로 저렇게 구성합니다. 

각 오브젝트마다 적절한 이름으로 고쳐주시고 sprite를 넣어주세요.

 

Anchors 프리셋을 모두 설정하고, position과 width, height를 모두 보기좋게 수정합니다.

Anchors 프리셋은 꼭!

 

 

 

 

 

NewScore 오브젝트는 최고점수일 경우에만 로직을 통해서 Active하기 위해 평소에는 false로 두기 위해서 인스펙터 창에서 체크를 풀어주세요. 

 

 

 

 

 

 

 

GameOver UI의 애니메이션을 만들어보려는데요, 플레이어가 바닥에 떨어지고 난 후에 GameOver UI가 전혀 보이지 않다가 크게 세번에 나뉘어 애니메이션이 실행됩니다. 

GameOver 글자 Image가 천천히 불투명하게 통통 튀는 듯하며 나타난다. --> Panel이 화면 아래서부터 올라와 위치한다. --> 아래 버튼 두개가 보인다. 

 

저는 다 감싸고 있는 GameOver UI의 화면에서 보이지 않게 y축의 position을 -1800으로 설정하였습니다.

 

이렇게 아래에 위치하고 게임 화면에는 보이지 않게 됩니다.

 

 

 

 

 

 

 

GameOver UI에 Animator를 만들고 애니메이션을 만듭니다. 애니메이션에서 맨 처음에 GameOver UI 자체의 Anchored Position의 y축을 0으로 만들어주세요. 그리고 Game Over 이미지가 동작을 하고, Panel이 올라오는 동작을 해야합니다.

GameOver UI가 y축이 0으로 올라왔는데, Panel과 버튼은 보이면 안되겠죠?

 

그래서 Panel은 Anchor Positon의 y축을 -1500에서 0으로 서서히 올라가는 동작을 하도록 하고, 버튼은 애니메이션의 처음에 Active를 false로 했다가 마지막에 true로 바꾸는 동작을 하면 됩니다. (Is Active라는 Property를 추가하여 사용)

 

물론 아까 위에처럼 GameOver UI의 Animator도 Trigger를 만들고, Any state와 애니메이션을 연결하고 수정해주세요!

 

 

 

 

 

 

 

이제 GameManager 스크립트를 수정해볼게요! 먼저 상단에 변수를 추가해주세요.

finalScoreText는 유니티에서 GameOverPanel의 FinalScore을 드래그해 넣어주면 됩니다. 

저는 Animator를 한번에 관리하려고 배열로 선언하였습니다. 

   public Text finalScoreText;
   public Animator[] anim;

 

유니티에서 Size를 적어주시고 Animator가 있는 오브젝트를 드래그해 넣어주세요.

 

 

 

public void GameOver()
    {
        //한번 실행
        if (!player.isDie)
        {
            anim[0].SetTrigger("GameOver");  //화면 반짝이는 애니메이션
            anim[2].SetTrigger("GameOverPanel");  //게임오버 panel 애니메이션
            
            //게임오버 UI       
            scoreText.enabled = false;  //스코어 text 안보이게하기
            finalScoreText.text = score.ToString();  //최종 점수
 
            //모든 오브젝트의 움직임을 멈춤
            om.StopObject("pillarUp");
            om.StopObject("pillarDown");
            om.StopObject("scoreZone");

            player.isStart = false;
            player.isDie = true;
            player.transform.rotation = Quaternion.Euler(0, 0, -90);
        }    
    }

GameOver 함수에서는 선언하였던 배열 anim를 적절히 사용하여주세요.

게임 오버 시에 반짝이는 애니메이터와 , GameOver UI의 애니메이터에서 만들었던 파라미터 Trigger를 통해 

애니메이션을 발동시킵니다. 

 

그 후에 게임화면 중앙에 있었던 scoreText는 보이지 않게 하기위해 enabled를 false로 바꾸어주세요.

게임이 끝났기 때문에 GameOverPanel에 띄울 최종 스코어를 score 변수로부터 가져옵니다.

 

기둥에 부딪힌 다음 바닥에 부딪히더라도 두번 실행되지 않게 if(!player.isDie)로 묶어주었습니다. 

 

나머지 아래 코드는 이전 포스트에서 작성했던 코드입니다.

GameOverPanel의 자식 오브젝트들의 로직에 대해서는 아래에 설명하겠습니다.

 

 

 

 

 

 

 

 

 

 

 

2. PlayerPrefs를 이용한 점수 데이터 저장, 점수에 따라 다른 메달, 재생 버튼 구현하기 

 

나중에 랭킹 Panel을 만들기도 해야하고, GameOverPanel에서도 최고점수를 나타내줘야 합니다.

그렇다면 이전의 게임 점수들이 데이터로 저장되어 있어야겠죠?

 

유니티에서는 데이터를 저장할 방법이 여러가지가 많습니다. 궁금하시다면 자세한 사항은 구글링을 해주세요!

저는 그중에서도 많은 데이터를 저장할 필요가 없고, 간단한 사용을 위한 PlayerPrefs 방법을 사용하겠습니다.

 

PlayerPrefs 클래스는 유니티에서 제공해주는 데이터 관리 클래스입니다.

int, float, string, bool 타입의 변수들을 저장하고 로드하는 기능을 제공합니다.

 

 

 

 

 

 

저는 랭킹 Panel에서 1등, 2등, 3등 까지 저장하여 보여주겠습니다. GameOver 가 되면 데이터를 저장해야겠죠?

일단 GameManager 스크립트를 수정하겠습니다. 

public void Save()  //점수 데이터를 저장함
    {
        if (score < PlayerPrefs.GetInt("BestScore")) {            
            if (score < PlayerPrefs.GetInt("SecondScore"))
            {               
                if (score < PlayerPrefs.GetInt("ThirdScore"))
                    return;  
                //3등일때
                PlayerPrefs.SetInt("ThirdScore", score);
                return;
            }
            //2등일때
            PlayerPrefs.SetInt("ThirdScore", PlayerPrefs.GetInt("SecondScore"));
            PlayerPrefs.SetInt("SecondScore", score);
            return;
        }
        //1등일때
        if (score == PlayerPrefs.GetInt("BestScore")) return;
        PlayerPrefs.SetInt("ThirdScore", PlayerPrefs.GetInt("SecondScore"));
        PlayerPrefs.SetInt("SecondScore", PlayerPrefs.GetInt("BestScore"));
        PlayerPrefs.SetInt("BestScore", score);
    }

PlayerPrefs의 SetInt는 지정한 키로 int 타입의 값을 저장하고, GetInt 는 지정한 키의 int 타입 값을 로드합니다.

저는 1등은 "BestScore", 2등은 "SecondScore", 3등은 "ThirdScore" 이라고 키를 정하여 데이터를 저장하였습니다.

Save라는 함수를 만들어 점수 데이터를 저장하게끔 했습니다.

 

예를 들어 score가 원래 저장되어있던 "BestScore"보다 크다면 그 score가 "BestScore"가 되고 원래 1등, 2등 점수는 2등,3등으로 밀려나겠죠? 그 점을 고려하여 로직을 짰습니다.

 

 

 

 

 

 

 

 

다음은 게임오버시에 GameOverPanel에 나올 메달의 종류를 정하는 함수를 만들어보겠습니다. 계속하여 GameManager의 스크립트를 수정하겠습니다.

일단, 메달 종류가 네가지가 있기 때문에 이 Sprite들을 저장해줄 배열을 만들고

그 sprite들을 넣어줄 원래의 Medal UI의 Image를 할당해보겠습니다.  

public Image medalUI;
public Sprite[] medalSprites;

medalUI에는 메달 UI (Image) 오브젝트를 드래그하여 넣고, Sprite[]는 Size를 4로 하고 메달 Sprite들을 찾아 드래그하여 넣어주세요.

 

 

 

void MedalDecide()
    {
        if (score >= 7) medalUI.sprite = medalSprites[0];
        if (score >= 10) medalUI.sprite = medalSprites[1];
        if (score >= 20) medalUI.sprite = medalSprites[2];
        if (score >= 30) medalUI.sprite = medalSprites[3];
    }

그리고 MedalDecide라는 함수를 하나 만들어 임의의 점수에 sprite가 바뀌게끔 해주세요.

 

 

 

 

 

 

 

 

GameManager 스크립트 상단에 변수를 추가하여주세요. BestScoreText는 GameOverPanel에 있는 최고 점수 Text를 유니티에서 할당하여주세요. newScore는 최고 점수일 경우에만 New라고 옆에 나타나는 그 Image UI를 넣어주세요. 

public Text BestScoreText;
public GameObject newScore;

 

 

그리고 GameOver 함수를 다음과 같이 수정해주세요.

 public void GameOver()
    {
        //한번만 실행
        if (!player.isDie)
        {
            anim[0].SetTrigger("GameOver");  //화면 반짝이는 애니메이션
            anim[2].SetTrigger("GameOverPanel");  //게임오버 panel 애니메이션

            //점수 데이터 저장
            Save();
            
            //게임오버 UI       
            scoreText.enabled = false;
            finalScoreText.text = score.ToString();
            BestScoreText.text = PlayerPrefs.GetInt("BestScore").ToString();
            MedalDecide();
            if (score == PlayerPrefs.GetInt("BestScore")) newScore.SetActive(true);  //최고 점수일 경우

            //모든 오브젝트의 움직임을 멈춤
            om.StopObject("pillarUp");
            om.StopObject("pillarDown");
            om.StopObject("scoreZone");

            player.isStart = false;
            player.isDie = true;
            player.transform.rotation = Quaternion.Euler(0, 0, -90);
        }    
    }

점수 데이터를 저장하기 위해 위에 만들었던 Save함수를 호출합니다.

 

BestScoreText의 text 값은 PlayerPrefs에 저장되어있는 "BestScore"의 int값을 가져와야 합니다.

MedalDecide 함수 또한 호출해주어 score에 맞는 메달을 나타내주고,

현재 게임의 점수가 "BestScore"의 값과 같다면 최고 점수인거겠죠? 그렇다면 New 이미지를 띄워주기위해

newScore 오브젝트를 활성화합니다.

 

나머지 코드는 그 전과 같습니다.

 

 

 

 

 

 

 

다음은 GameOverUI의 재생버튼을 구현해보겠습니다. 다시 게임을 시작하는 것이기 때문에 단순히 현재 Scene을 다시 로드하면 됩니다. 다시 GameManager 스크립트를 수정하겠습니당

using UnityEngine.SceneManagement;

ScneneManager를 사용하기 위해 추가해주세요.

 

 

public void Retry() //게임을 다시 시작함
    {
        SceneManager.LoadScene(1);
    }

그리고 Retry 함수를 만들어주세요. SceneManager의 LoadScene을 호출합니다. 이 때 인수는 int형으로 인덱스를 말합니다. 이 인덱스는 무엇이냐!

 

 

 

유니티 메뉴에서 File - Build Settings 에 들어가면 위에 Scenes In Build라고 보이죠? 그곳에 사용할 Scene을 Add Open Scenes 버튼을 눌러 추가해주면 됩니다. 저는 메인메뉴까지 만들었기 때문에 게임진행 Scene (Stage) 인덱스가 1입니다.

 

 

 

 

 

 

이제 저 Retry함수를 어떻게 적용할 것인가 보여드리겠습니다.

그 재생버튼의 인스펙터창에서 OnClick()를 수정할건데요, +를 누르고 GameManager 오브젝트를 드래그하여 넣어주세요! 그 후에 파란색 동그라미 안의 창을 눌러 GameManager - Retry() 를 지정하면 됩니다.

그러면 이제 버튼을 누를 시에 지정한 함수가 실행된답니당

 

 

 

 

 

 

 

 

 

3. 랭킹 Panel UI 구현, 점수 데이터 로드하기 

 

재생버튼 옆에 있는 이 랭킹 버튼을 누르면 랭킹 Panel이 보이면서 점수 순위가 나타나야합니다.

 

 

제가 대충 만든 랭킹 Panel은 이와 같습니다.

 

 

 

 

Canvas 안에 RankingUI (Image)를 생성합니다.  

Ranking UI

① Ranking 글자 (Text)

② Best : 1이라는 숫자 (Image)

③ BestScoreLoad : 저장된 1등 점수 (Text)

④ Second : 2라는 숫자 (Image)

⑤ SecondScoreLoad : 저장된 2등 점수 (Text)

Third: 3이라는 숫자 (Image)

⑦ ThirdScoreLoad : 저장된 3등 점수 (Text)

⑧ OkBtn : 누르면 이전 화면으로 나감 (Button)

 

역시나 Anchor 프리셋을 설정해주시고 적절하게 Position과 width, height을 설정해주세요.

Text들은 글자 크기와 색깔을 설정해주세요. Image와 Button에 들어갈 Sprite들을 적절히 찾아 드래그하여 넣어주세요.

 

 

 

 

 

 

저기에 나타날 점수들은 PlayerPrefs에 저장된 데이터를 로드해야겠죠?

GameManager 스크립트를 바로 수정해보겠습니다.

public Text[] scoreData;

Text를 배열로 관리하여 유니티에서 Size를 3으로 정하시고,

BestScoreLoad, SecodnScoreLoad, ThirdScoreLoad 텍스트 오브젝트들을 넣어주세요.

 

 

 

 

그리고 Load함수를 하나 만들겠습니당. Text 배열의 각 인덱스에 순서대로 값을 넣어주어 text 값을 바꿔줍니다.

private void Load() //랭킹 Panel의 text에 점수를 로드
    {
        scoreData[0].text = PlayerPrefs.GetInt("BestScore").ToString() + "점";
        scoreData[1].text = PlayerPrefs.GetInt("SecondScore").ToString() + "점";
        scoreData[2].text = PlayerPrefs.GetInt("ThirdScore").ToString() + "점";
    }

그리고 GameOver 함수에 Save(); 밑에 Load 함수를 호출해주시면 됩니다. 

 

 

 

 

 

평소에 랭킹 Panel이 안보여야하기 때문에 RankingUI를 비활성화해주세요.

 

그리고 버튼을 눌렀을 때, 랭킹 Panel이 보여야합니다.

버튼 인스펙터창의 OnClick()에서 +를 누르고 RankingUI 오브젝트를 드래그하여 넣어주세요.

파란색 줄 창을 누르고 GameObject - SetActive 를 지정해주세요. 활성화/비활성화 정할 수 있어요!

아래 체크박스를 체크하면 true, 체크 안하면 false 입니다. 버튼을 누르면 활성화시켜야 하기 때문에 체크해주세요.

 

 

 

그리고 RankingUI 의 Ok 버튼도 똑같이 하면 됩니다!

누르면 랭킹 Panel이 비활성화가 되어야하기 때문에 체크를 풀어주세요.

 

 

 

 

 

 

오늘 포스트는 여기까지 쓰고..!😰

다음 포스트에서는 메인메뉴, 효과음, 캐릭터/배경 랜덤 설정 등을 해보겠습니당😊😊!

감사합니당~

반응형
댓글
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday