오늘은 저번에 이어서 Timer 추가와 게임 종료 화면을 만들었다.

 

<UI> - Timer

저번 스크럼 때 회의 결과, GameManager 스크립트는 각각의 이름으로 만든 뒤, 나중에 한 번에 합치기로 했다.

위 스크립트를 GameManager 오브젝트에 컴포넌트하고 timeTxt 변수에 Text 오브젝트를 할당한다.

public Text timeTxt;
float time;

private void Update()
{
    time += Time.deltaTime;
    timeTxt.text = time.ToString();
}

 

그런데 할당이 안되는 문제가 발생했다. UnityEngine.UI 네임스페이스도 잘 추가 되어있고 변수명 등 오타가 나지도 않았는데 timeTxt에 Text 오브젝트가 추가가 안됐다. 계속 헤맨 결과, 알고보니 레거시 형태의 Text를 추가했기 때문이었다.

Text 대신 TextMeshPro를 사용하는 경우, 스크립트에서도 TextMeshProUGUI를 사용해야한다.

public TMP_Text timeTxt;
float time;

private void Update()
{
    time += Time.deltaTime;
    timeTxt.text = time.ToString();
}

 

이렇게 하면 0.00으로 타임 표시가 된다.

 

그러나 내가 원하는 것은 00:00 형식이었기 때문에 string.Format 메서드를 사용하여 형식이 지정된 문자열을 만든다.

private void Update()
{
    time += Time.deltaTime;
    int min = (int)time % 3600/60;
    int sec = (int)time % 3600%60;
    timeTxt.text = string.Format("{0:D2}:{1:D2}", min, sec);
}

"{0:D2}:{1:D2}"가 형식 문자열로 0, 1은 각각 몇 번째 인수인지, D2는 십진수를 의미한다.

 

시간까지 표현하고 싶다면 추가해주면 된다.

private void Update()
{
    time += Time.deltaTime;
    int hour = (int)time / 3600;
    int min = (int)time % 3600/60;
    int sec = (int)time % 3600%60;
    timeTxt.text = string.Format("{0:D2}:{1:D2}:{2:D2}", hour, min, sec);
}

 

 

<게임 종료 화면>

게임 종료 화면은 UI Panel로 만들기로 했다.

종료 화면의 내용은 버틴 시간과 다시하기, 메인으로 가는 버튼으로 구성되어있다. 일단 껍데기를 만들어준다.

 

게임 종료 화면은 게임 오버가 됐을 때 떠야하므로 꺼둔다.

 

이제 게임이 끝났을 때 화면이 나타나도록 하기 위해 GameManager를 싱글톤 처리한다.

싱글톤이란 하나의 인스턴스만 생성하고 그 인스턴스에 대해 전역적인 접근을 제공하는 것이다.

public static gameManager I;

void Awake()
{
    if (I == null)
    {
        I = this;
    }
    else
    {
        Destroy(gameObject);
    }
    // 현재 게임 오브젝트를 새로운 씬으로 이동해도 파괴되지 않도록 설정
    DontDestroyOnLoad(gameObject);
}

 

 

게임이 종료되면 시간을 멈추고 endPanel이 켜지도록 한다.

public GameObject endPanel;

public void GameOver()
{
    Time.timeScale = 0;
    endPanel.SetActive(true);
}

Time.timeScale이 0이면 시간이 멈추고 1이면 진행된다. 궁금해서 찾아보니 음수 값을 넣으면 0으로 처리되며 0.5는 2배 느려지고 2를 넣으면 2배, 3을 넣으면 3배 등 배속이 되도록 처리된다고 한다.

 

Update()와 gameOver 간의 시간차가 있기 때문에 게임오버가 되자마자 시간을 멈추기 위해 isRunning이라는 불값을 선언해주고 true로 설정한 뒤, 살아있을 때만 업데이트 되도록 한다.

private bool isRunning = true;

private void Update()
{
    if (isRunning) // 게임실행 중에 시간이 간다
    {
        // 타이머 표시
        time += Time.deltaTime;
        int hour = (int)time / 3600;
        int min = (int)time % 3600 / 60;
        int sec = (int)time % 3600 % 60;
        timeTxt.text = string.Format("{0:D2}:{1:D2}:{2:D2}", hour, min, sec);
    }
}

public void GameOver()
{
    isRunning = false; // 시간 멈추기
    Time.timeScale = 0f;
    endPanel.SetActive(true);
    
    // 게임오버 시간 = 현재 시간
	currentScoreTxt.text = timeTxt.text;
}

 

버튼을 눌렀을 때 각각 Retry, Main의 기능을 하도록 메서드를 만들어준다.

using UnityEngine.SceneManagement;

// retry 버튼을 누르면 현재 씬이 다시 로드되도록 한다
public void Retry()
{
    SceneManager.LoadScene("MainGame");
}

// main 버튼을 누르면 메인화면을 부른다
public void MainTitle()
{
    SceneManager.LoadScene("FirstTitle");
}

 

버튼을 눌렀을 때, Scene이 로드 되지 않고 오류가 뜬다면 File - Build Settings에서 해당 Scene이 추가 되어있는지 확인해보자.

 

확인 결과 잘 작동한다. 아직 플레이어가 게임 오버 됐을 때 부분이 없기 때문에 그 부분을 담당한 분과 합쳐서 확인해보아야 할 것 같다.

 

작업하면서 어려웠던 점은 위에서 언급했다시피 협업할 때 아직 구현이 되지 않은 부분을 임시로 돌려보려면 어떻게 처리해야하는지가 곤란했다. 그리고 TMP(TextMeshPro)를 사용할 때, 스크립트에서 레거시 Text를 처리하는 방법과 달라 자꾸 헷갈렸다. 현재 시간과 게임 오버 시간을 처리할 때도 그 점을 잊.text를 빼먹어서 오류가 떴었다.

+ Recent posts