본문 바로가기
도전! N잡러!/도전! 게임 개발!

TAP FLOAT 개발 일기 #13

by NAWE 2023. 10. 5.
반응형

안녕하세요. 나위입니다.

STUDIO NAWE의 첫 타이틀. TAP FLOAT의 개발 일기를 찾아주셔서 감사합니다.

 

이전 포스팅에서 이어지는 내용이오니, 못 보신 분들은 아래 링크로 앞 내용을 먼저 보고 오시는 게 좋겠어요!

어서오세요! TAP FLOAT 개발 일기입니다!


TAP FLOAT 개발 일기 #0 바로가기 ◀

TAP FLOAT 개발 일기 #1 바로가기 ◀

TAP FLOAT 개발 일기 #2 바로가기 ◀

TAP FLOAT 개발 일기 #3 바로가기 ◀

TAP FLOAT 개발 일기 #4 바로가기 ◀

TAP FLOAT 개발 일기 #5 바로가기 ◀

TAP FLOAT 개발 일기 #6 바로가기 ◀

TAP FLOAT 개발 일기 #7 바로가기 ◀

TAP FLOAT 개발 일기 #8 바로가기 ◀

TAP FLOAT 개발 일기 #9 바로가기 ◀

TAP FLOAT 개발 일기 #10 바로가기 ◀

TAP FLOAT 개발 일기 #11 바로가기 ◀

TAP FLOAT 개발 일기 #12 바로가기 ◀

 

그럼, 시작합니다!


완성한 GAME OVER 화면이 제대로 동작할 수 있도록 하기 위해서, 앞서 만들어 두었던 'GameManager' 스크립트를 손보려고 해요.

아직까지는 Game Manager의 기능이 점수를 관리하는 기능과 게임의 종료를 선언하는 기능 뿐이지만, 앞으로는 더 많은 기능이 추가될 예정이랍니다.

그 중 하나가 지금부터 만들 'GAME OVER 화면을 보여줘!' 기능이 되겠네요.

 

그러기 위해서는 기존의 만들어 둔 Gameover Panel 을 일반적인 상황에서는 보이지 않도록 처리할 필요가 있겠어요.

어떻게 하냐고요? 간단합니다.

Hierarchy에서 Gameover Panel 오브젝트를 선택한 뒤, Inspector에서 최상단에 보이는 체크 박스를 해제하기만 하면 되요.

체크 표시를 해제합시다.

 

그렇게 하면 짜쟌.

만들어 둔 GAME OVER 화면이 사라지게 됩니다.

저는 저렇게 화면 활성화 / 비활성화 기능을 이용해서, '조니'가 사라질 때 Gameover Panel을 활성화시키려고 해요.

 

그렇게 제작한 스크립트 전문은 아래와 같습니다.

using UnityEngine;
using UnityEngine.UI;

public class GameManager : MonoBehaviour
{
    public static GameManager instance = null;
    
    [HideInInspector]
    public bool isGameOver = false;
    
    [SerializeField]
    private GameObject pointPanel;
    [SerializeField]
    private GameObject gameOverPanel;
    [SerializeField]
    private Text gameOverScoreText;
    [SerializeField]
    private Text gameOverBestScoreText;
    [SerializeField]
    private Text pointText;
    public float pointPerTime = 0.1f;
    public float addPoint = 0.1f;

    [HideInInspector]
    public float point = 0f;
    private float timer = 0f;
    private float bestScore = 0f;

   void Awake()
   {
       if(instance == null)
       {
           instance = this;
       }
   }

    void Update()
    {
        if(!isGameOver)
        {
            timer += Time.deltaTime;
        }

        if(timer > pointPerTime)
        {
            point += addPoint;
            timer = 0f;
            UpdatePointText();
        }
    }

    void UpdatePointText()
    {
        pointText.text = point.ToString("F1") + "m";
    }
    
	public void SetGameOver()
    {
        isGameOver = true;

        Spawner spawner = FindObjectOfType<Spawner>();
        if(spawner != null)
        {
            spawner.StopEnemyRoutine();
        }

        Invoke("ShowGameOverPanel", 0.4f);
    }
    
	void ShowGameOverPanel()
    {
        gameOverPanel.SetActive(true);
        pointPanel.SetActive(false);
        gameOverScoreText.text = point.ToString("F1") + "m";
        gameOverBestScoreText.text = bestScore.ToString("F1") + "m";
    }
}

이전에 비해 상당히 많은 양이 추가된 것을 보실 수 있을 겁니다.

스크롤의 압박이 심해 가슴이 두근거리실 수 있겠지만, 그리고 뭔 소린지 모를 말들이 많아 보여 현기증을 느끼실 수도 있으시겠지만...!

 

차근차근 따져보면 크게 어려운 것들이 아니란 사실을 알게 될 겁니다.

저도 불과 얼마 전까지는 '저게 무슨 외계어들이야...?'라고 받아들이던 사람들 중 하나였으니까, 믿으셔도 됩니다.

 

우선, 새로운 개념이 하나 등장했습니다.

바로 '싱글톤''Instance'라는 것인데요. 어떤 개념이냐면 대략 이런 겁니다.

 

 

"플레이어가 죽을 때 게임 오버 패널을 띄워야 하는데."

 

"그런데 게임 오버 패널을 띄우는 함수는 Game manager에 있는데? Player 스크립트에서도 똑같이 작성해야 하나?"

 

"Game manager 스크립트에 있는 코드를 가져다 쓰게 할 순 없는가...?"

 

 

이런 상황(?)에서 Game Manager가 Instance화 되어 있다면, Game Manager의 함수를 불러와서 사용할 수 있게 하는 것이죠! 틀렸다면 죄송합니다. 누가 저한테도 잘 좀 설명해주면 좋겠어요..

 

한마디로 코드를 복잡하게 만들지 않도록, 다른 스크립트의 함수를 가져와서 쓸 수 있게 만드는 기능인데 사용법은 이러합니다.

    public static GameManager instance = null;

1. 위의 코드를 변수 선언부에(주로 가장 위에) 작성한다.

 

   void Awake()
   {
       if(instance == null)
       {
           instance = this;
       }
   }

2. 위의 코드를 내용에 추가한다.

 

Awake라는 것은 Start나 Update와 마찬가지로, 유니티에서 제공하는 기본 함수입니다.

다만 Start보다 한 타이밍 더 빠르게 실행하는 함수라는 개념이죠.

때문에 Awake 안에 있는 내용들은 Start 안에 있는 내용보다 더 빨리 실행되고, 준비시킬 수 있게 됩니다.

 

저 코드의 해석은 이러합니다.

 

"만약에 인스턴스 안에 아무런 값이 없다면, 이 오브젝트(지금 상황에서는 Game manager)를 instance에 넣도록 해라."

 

결국 Gama Manager를 Instance로 만든다는 의미이기도 합니다.

 

그리고, 새로 추가된 변수들은 아래와 같습니다.

    [HideInInspector]
    public bool isGameOver = false;
    
    [SerializeField]
    private GameObject pointPanel;
    [SerializeField]
    private GameObject gameOverPanel;
    [SerializeField]
    private Text gameOverScoreText;
    [SerializeField]
    private Text gameOverBestScoreText;
    private float bestScore = 0f;

isGameOver은 게임 오버 여부를 판단합니다. true 혹은 false로 지정되는데, 초기값은 false로 지정합니다.

GameObject pointPanel은 게임 화면에 나타나는 PointPanel이 게임 오버 화면에서는 보여지면 안되니까, 활성화 / 비활성화 여부를 조절하기 위해 변수로 등록해두려고 합니다.

GameObject gameOverPanel도 같은 의미입니다. 게임 중에는 비활성되어야 하고, 게임 오버 시에는 활성화되어야 하기에 변수로 미리 등록해두는 것입니다.

gameOverScoreText는 게임 오버 화면에서 나타나는 점수 표시 Text를 연결시켜 직전 게임의 점수를 보여주려는 것이고,

gemeOverBestScoreText도 마찬가지로 게임 오버 화면의 최고 기록 점수를 보여주기 위한 용도입니다.

마지막으로 bestScore라는 것은, 최고 점수를 저장할 수 있도록 미리 변수를 만든 것입니다. 디폴트 값은 0으로 지정했어요.

 

다음으로, Update의 점수를 누적해주는 코드에 변화가 생겼습니다.

        if(!isGameOver)
        {
            timer += Time.deltaTime;
        }

만약, 게임 오버가 ture가 아니라면 (!는 not의 의미입니다.) 타이머를 진행시키도록 해라. 라는 의미가 되어버렸죠.

게임 오버 상태일 때에는 점수가 누적되면 안되기 때문에 별도로 막음 처리한 것입니다.

 

다음으로 추가한 내용은 이것입니다.

    public void SetGameOver()
    {
        isGameOver = true;

        Spawner spawner = FindObjectOfType<Spawner>();
        if(spawner != null)
        {
            spawner.StopEnemyRoutine();
        }

        Invoke("ShowGameOverPanel", 0.4f);
    }

SetGameOver라 이름붙인 함수입니다.

이것은 말 그대로, 게임 종료 화면이 뜨기 전에 처리해야 할 것들을 처리해서 '게임 종료를 준비시키는' 함수이죠.

내용은 이러합니다.

 

 

"게임 오버 상태를 True로 바꿔."

 

"게임 오브젝트 중 Spawner을 찾아서 Spawner에 연결해 줘."

 

"만약 spawner가 없지 않다면 (존재한다면), spawner의 StopEnemyRoutine함수를 실행시켜."

 

"그리고 ShowGameOverPanel 함수를 0.4초 후에 실행시켜."

 

 

StopEnemyRoutine라는 것은 예전에 Spawner를 만들면서 추가해 두었던 함수였죠.

개발일기 #8에서 그 내용이 있었습니다.

 

결국 저 내용은 더 이상 방해요소(Enemy)가 재생성되지 않도록 막는 코드라고 볼 수 있겠습니다.

 

다음으로 추가된 내용은, ShowGameOverPanel.

바로 게임오버 패널을 보이도록 만드는 코드이죠.

 

내용은 이러합니다.

    void ShowGameOverPanel()
    {
        gameOverPanel.SetActive(true);
        pointPanel.SetActive(false);
        gameOverScoreText.text = point.ToString("F1") + "m";
        gameOverBestScoreText.text = bestScore.ToString("F1") + "m";
    }

게임 오버의 SetActive. 활성화 상태를 true로 바꿔라.

스크롤 패널의 활성화 상태를 false. 숨기도록 해라.

게임오버 스코어에 게임 스코어를 보여주도록 해라.

게임오버 베스트스코어에 최고 점수를 보여주도록 해라.

 

간단하죠?

모두 변수 선언 시에 등록했던 게임 오브젝트를 관리하는 함수라고 할 수 있겠습니다.


이렇게 스크립트 수정을 완료했으니, 이제는 엔진 상에서 실제 게임 오브젝트와 변수로 등록한 게임 오브젝트들을 서로 연결시키는 작업을 해야겠네요.

 

 

<다음 편에 계속>

반응형

'도전! N잡러! > 도전! 게임 개발!' 카테고리의 다른 글

TAP FLOAT 개발 일기 #15  (93) 2023.10.12
TAP FLOAT 개발 일기 #14  (82) 2023.10.11
TAP FLOAT 개발 일기 #12  (109) 2023.10.04
TAP FLOAT 개발 일기 #11  (120) 2023.09.26
TAP FLOAT 개발 일기 #10  (98) 2023.09.25

댓글