Coding Feature.

[Unity 3D] 3D 퐁 만들기 #3 UI 매니저(메인 메뉴, 게임 오버), 공 트레일 추가, 코드 리팩토링 본문

Toy Project/MICRO-PONG [Unity3D]

[Unity 3D] 3D 퐁 만들기 #3 UI 매니저(메인 메뉴, 게임 오버), 공 트레일 추가, 코드 리팩토링

codingfeature 2024. 1. 19. 17:29

메인 메뉴, 게임 오버 그리고 게임 플레이 도중 화면에 나타나는 UI 관련 요소를 제어하는 UI 매니저를 구현해보겠습니다.

 

우선 메인 메뉴와 게임 오버, 그리고 게임 플레이는 각 별개의 Scene으로 구분짓지 않고 한 씬 내에서 관리하도록 하겠습니다.

 

 

Main Menu와 Game Over 그리고 Game Panel 이름의 Panel 세 개를 만들었습니다.

 

그리고 UI Manager를 아래와 같이 작성했습니다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIManager : MonoBehaviour
{
    private static UIManager instance;

    GameObject m_mainMenu;
    GameObject m_GameOver;
    GameObject m_GamePanel;

    public GameObject scoreText;
    public GameObject finalScoreText;
    public GameObject highScoreText;

    public enum Panels
    {
        MainMenu,
        GameOver,
        GamePanel,
        SetAllPanelsFalse
    }

    public static UIManager Instance
    {
        get
        {
            return instance;
        }
    }

    private void Awake()
    {
        if (instance)
        {
            Destroy(instance);
            return;
        }

        instance = this;
        DontDestroyOnLoad(this.gameObject);


        scoreText = GameObject.Find("Canvas/Game Panel/Score");
        finalScoreText = GameObject.Find("Canvas/Game Over/Final Score");
        highScoreText = GameObject.Find("Canvas/Game Over/High Score");

        m_mainMenu = GameObject.Find("Canvas/Main Menu");
        m_GameOver = GameObject.Find("Canvas/Game Over");
        m_GamePanel = GameObject.Find("Canvas/Game Panel");
    }

    public void SetPanels(Panels panel)
    {
        switch (panel)
        {
            case Panels.MainMenu:
                m_mainMenu.SetActive(true);
                m_GameOver.SetActive(false);
                m_GamePanel.SetActive(false);
                break;
            case Panels.GameOver:
                m_mainMenu.SetActive(false);
                m_GameOver.SetActive(true);
                m_GamePanel.SetActive(false);
                break;
            case Panels.GamePanel:
                m_mainMenu.SetActive(false);
                m_GameOver.SetActive(false);
                m_GamePanel.SetActive(true);
                break;
            case Panels.SetAllPanelsFalse:
                m_mainMenu.SetActive(false);
                m_GameOver.SetActive(false);
                m_GamePanel.SetActive(false);
                break;
            default:
                break;
        }
    }

    public void SetScoreTextAlpha(float alpha)
    {
        Color color_alphaZero = scoreText.GetComponent<Text>().color;
        color_alphaZero.a = alpha;
        scoreText.GetComponent<Text>().color = color_alphaZero;
    }

    public void SetScoreText(int score)
    {
        scoreText.GetComponent<Text>().text = "" + score;

    }

    public void SetHighScoreText(int highScore)
    {
        highScoreText.GetComponent<Text>().text = "HIGH SCORE\n" + highScore;
    }

    public void SetFinalScoreText(int finalScore)
    {
        finalScoreText.GetComponent<Text>().text = "" + finalScore;
    }

    public IEnumerator ShowScore()
    {
        yield return null;
        float text_alpha = 1.0f;

        UIManager.Instance.SetScoreText(GameManager.Instance.score);

        while (text_alpha > 0.0f)
        {
            SetScoreTextAlpha(text_alpha);
            text_alpha -= 0.01f;
            yield return new WaitForSeconds(0.01f);
        }
    }
}

 

UI 매니저 내의 함수를 통해 각 Panel을 화면에 보이게 하거나, Score의 Text를 바꿀 수 있도록 했습니다.

 

그리고 플레이어 스크립트에서 작성했었던 점수 코루틴를 UI 매니저로 옮겼습니다.

그래서 플레이어 스크립트는 다음과 같이 코루틴을 호출하면 되겠죠!

 

public class PlayerScript : MonoBehaviour
{
    GameObject ball;
    private void Awake()
    {
        ball = GameObject.Find("Ball");
    }
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("Ball"))
        {
            GameManager.Instance.score += 1;

            ball.GetComponent<BallScript>().AddBallSpeed(GameManager.Instance.ballSpeedIncrement);
            StartCoroutine(UIManager.Instance.ShowScore()); // 코루틴 호출
        }
    }
}

 

 

그리고 게임 매니저 코드를 리팩토링 했습니다.

public class GameManager : MonoBehaviour
{
..
..
    void Start()
    {
        InitializeSettings();
        highScore = 0;
        UIManager.Instance.SetPanels(UIManager.Panels.MainMenu);

        Time.timeScale = 0f;
    }
    
    public void StartGame()
    {
        isGameOn = true;

        UIManager.Instance.SetPanels(UIManager.Panels.GamePanel);

        Time.timeScale = 1f;
    }

    public void RestartGame()
    {
        InitializeSettings();

        UIManager.Instance.SetPanels(UIManager.Panels.GamePanel);

        isGameOn = true;
        Time.timeScale = 1f;
    }

    void InitializeSettings() // 게임 매니저 내 변수 값 false 또는 0으로 초기화.
    {
        isGameOn = false;
        isGameOver = false;

        score = 0;
        UIManager.Instance.SetScoreText(score);
        UIManager.Instance.SetScoreTextAlpha(0f);
        UIManager.Instance.SetPanels(UIManager.Panels.SetAllPanelsFalse);

        m_ball.GetComponent<BallScript>().SetBallSpeed(initBallSpeed);
        m_ball.GetComponent<BallScript>().SetBallVector(initBallVector);
        m_ball.GetComponent<BallScript>().SetBallPosition(initBallPosition);
    }
    public void HandleGameOver()
    {
        isGameOn = false;
        isGameOver = true;

        if (score > highScore)
        {
            highScore = score;
        }

        UIManager.Instance.SetHighScoreText(highScore);
        UIManager.Instance.SetFinalScoreText(score);
        UIManager.Instance.SetPanels(UIManager.Panels.GameOver);

        Time.timeScale = 0f;
    }
}

 

게임 매니저에서 각 게임 상태를 함수로 표현하고 UI 매니저의 함수를 이용해서 UI Element들을 변경하게 됩니다.

 

 

이제 공에 트레일을 추가해서 공이 이동한 경로를 시각화해보겠습니다.

이는 유니티의 Trail을 사용했습니다.

 

 

 

 

 

다음은 게임이 시작될 때 공의 처음 이동 벡터, 위치를 랜덤값으로 초기화하는 로직과, 게임에 효과음, 배경음악을 관리할 수 있는 사운드 매니저를 구현해보겠습니다!