[Unity] 개인과제 - TopDown2D

Gee·2025년 2월 20일

트러블 슈팅

미니게임 FlappyPlane

미니게임에 입장하면 Click To Start 문구가 표시되고, 게임이 종료되면 Game Over 문구와 함께 재시작 버튼, 메인 이동 버튼이 보이게 만들었다.

그런데 게임 오버 시 위 이미지처럼 시작 시에만 표시돼야 하는 Click To Start가 함께 뜨는 문제가 발생했다.
관련 코드를 보면 이렇다.

	<UI 스크립트>
    
    // 게임 오버 시 재시작 안내 문구를 표시하는 함수
    public void SetStart(bool show)
    {
        startText.gameObject.SetActive(show);  // 시작 텍스트 활성화
    }

    // 게임 오버 시 게임 오버 문구 및 버튼 표시하는 함수
    public void SetGameOverUI()
    {
        startText.gameObject.SetActive(false);      // 시작 문구 숨기기
        gameOverText.gameObject.SetActive(true);    // 게임 오버 문구 활성화
        restartButton.gameObject.SetActive(true);   // 재시작 버튼 활성화
        mainButton.gameObject.SetActive(true);      // 메인 버튼 활성화
    }

    // 재시작 버튼 클릭 시 호출되는 함수
    private void OnRestartClicked()
    {
        GameManager.Instance.RestartGame();
    }

    // 메인 버튼 클릭 시 호출되는 함수
    private void OnMainClicked()
    {
        GameManager.Instance.GoToMenu();
    }
	<Game Manager 스크립트>
    
    // 미니게임 입장 시 보여줄 세팅
    private void Start()
    {
        Time.timeScale = 0;  		// 게임을 멈춤
        uiManager.UpdateScore(0);   // 게임 시작 시 점수를 0으로 설정하고 UI에 반영
        uiManager.SetStart(true);   // UI 매니저의 재시작 버튼 활성화
    }

    private void Update()
    {
        if (!gameStarted) // 아직 게임이 시작되지 않았다면
        {
            if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space))
            {
                StartGame();	// 키 입력 시 게임 시작
            }
        }
    }

	// 게임 실행 시
    private void StartGame()
    {
        gameStarted = true;
        uiManager.SetStart(false);  // "Click to Start" 문구 숨기기
        Time.timeScale = 1;  // 게임 시작
    }

    public void GameOver()
    {
        uiManager.SetStart(false);     // 게임 오버 시 "Click to Start" 문구 숨기기
        uiManager.SetGameOverUI();     // UI 매니저의 재시작 버튼 활성화
    }

    public void RestartGame()
    {
        // 현재 활성화된 씬(게임 씬)을 다시 로드하여 게임을 재시작
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }

    public void GoToMenu()
    {
        SceneManager.LoadScene("SampleScene");  // 메인 씬으로 이동
    }
}   

시도

SetStart(bool show)
미니게임 씬 입장 시에 startText를 보여주고, 게임이 시작되면 해당 문구를 꺼주기 위해 bool로 세팅했다.
처음엔 여기에 bool값을 잘못 입력했나 싶어서 고쳐봤는데 이 문제는 아니었다.

    // 게임 오버 시 게임 오버 문구 및 버튼 표시하는 함수
    public void SetGameOverUI()
    {
        startText.gameObject.SetActive(false);      // 시작 문구 숨기기
        restartText.gameObject.SetActive(true);     // 게임 오버 문구 활성화
        restartButton.gameObject.SetActive(true);   // 재시작 버튼 활성화
        mainButton.gameObject.SetActive(true);      // 메인 버튼 활성화
    }

SetGameOverUI()
게임 오버 시에는 startText를 끄도록 설정해 줬는데 계속해서 켜지는 상황..
GameManager.cs 에서 게임 오버 시 해당 SetStart를 꺼줘도 봤는데 변화는 없었다.
코드상으로는 문제가 없어 보여 디버그 로그를 찍어보니 게임 오버 시 Start가 게임 종료 시 두 번씩 호출되고 있었다.
그외에도 GameManager에 등록해 놓은 메서드들이 두 번, 세 번씩 실행됨

원인

문제는 싱글톤화 한 GameManager.cs를 미니게임 씬 내 Canvas나 Button등 여러 곳에 중복으로 붙여놓아서 또다시 함수들이 호출된 것.
싱글톤 패턴을 사용한 스크립트는 반드시 하나만 유지되어야 하는데 그걸 지키지 않아 생긴 문제였다.

해결

미니게임 씬 내 RestartButton, MainButton, Canvas에 첨부한 GameManager 스크립트를 모두 제거하고 GameManager 오브젝트에만 스크립트 부여하니 해결되었다.
추가적으로 버튼 기능을 구현하려 할 때, 아무 생각 없이 버튼 안에다가 또 GameManager 스크립트를 첨부하고 기능을 동작시키려 해서 생긴 문제.

예외처리

기본적으로 싱글톤은 하나만 존재해야 하지만, 여러 곳에 쓰였을 때 Awake()에서 새로 생성된 GameManager를 제거하도록 처리해 줄 수도 있다.

private void Awake()
{
    if (gameManager == null)
    {
        gameManager = this;
        DontDestroyOnLoad(gameObject); // 씬 변경 시에도 유지
    }
    else if (gameManager != this)  // 이미 존재하는 인스턴스가 자신이 아니라면
    {
        Destroy(gameObject);  // 중복된 GameManager 삭제
        return;
    }
    
    // UIManager가 싱글톤인지 여부에 따라 다르게 처리
    if (UIManager.Instance != null)
    {
        uiManager = UIManager.Instance;  // 싱글톤 사용
    }
    else
    {
        uiManager = FindObjectOfType<UIManager>();  // 싱글톤이 아니라면 씬에서 찾아서 사용
    }
}

이렇게 해주면 GameManager가 중복으로 생성되지 않아 UI가 여러번 조작되는 문제를 방지할 수 있다.

profile
...

0개의 댓글