오늘은 저번에 이어서 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를 빼먹어서 오류가 떴었다.
'부트캠프 > Project' 카테고리의 다른 글
<프로젝트> 팀과제 Unity 2D 게임 - Space Survival(5) (1) | 2023.12.06 |
---|---|
<프로젝트> 팀과제 Unity 2D 게임 - Space Survival(4) (1) | 2023.12.05 |
<프로젝트> 팀과제 Unity 2D 게임 - Space Survival(1) (0) | 2023.11.30 |
<프로젝트> Unity 2D 게임 개발 (1) | 2023.11.29 |
<프로젝트> 팀과제 TextRPG 계획(5) (0) | 2023.11.23 |