유니티 부트캠프 8기/Ch04. Unity 게임 개발 입문

미니게임 추가, 이벤트 트리거를 통한 미니게임 실행, 게임 관련 UI, GameObject.Find와 transform.Find, Resources.FindObjectsOfTypeAll<T> 메서드 차이, LoadScene 다음에 호출되는것, DontDestroyOnLoad 한 뒤에 매니저의 자식으로 된 것을 다시 연결하는 방법

Imperor 2025. 2. 19. 22:22

이부분도 손이 많이갔다

 

UI를 코드로 연결하는 것이 어려웠다

 

왼쪽의 Fish에 닿으면 트리거가 작동하여 원래 비활성화된 FishUI가 활성화되고 그 아래에 있는 

빈 게임오브젝트인 EnterMini_1을 활성화하고 UI를 보여준다

클릭하면 게임이 실행되고, EnterMini_1을 비활성화한다

 

게임을 종료하고 다시 돌아오면 ExitMini_1을 활성화하여 게임 결과를 보여주는 방식이다

문제는

씬을 바꾸어 로드할때 참조가 해제되는 점인데

이를 막기 위해서

FishUI는 매번 Start에서 자식의 오브젝트에서 EnterMini_1과 ExitMini_1을 연결해야한다

FishUI는 씬이 바뀔때마다 호출되어 자식오브젝틑를 찾아서 연결해야 하므로 Start메서드가 있어야한다

연결한 다음에도 또 자식에 접근하여 BFScoreText나 TFScoreText에 접근해 점수를 기록해야한다

 

맨 처음 미니플젝1에서 자물쇠 따는거랑 비슷한데

이건 조금 다른게, 둘의 자식에 있는 Text에 접근하여 점수를 기록해야한다

 

    public override void Init(UIManager uiManager)
    {
        base.Init(uiManager);
        bestFlappyScoreText = transform.Find("BFScoreText").GetComponent<TextMeshProUGUI>();
        thisFlappyScoreText = transform.Find("TFScoreText").GetComponent<TextMeshProUGUI>();
    }

 

하지만... 찾아오질 못하네?

이유는 transform.Find는 자기 자신을 기준으로 경로를 들어가는데 BFScoreText는 없기 때문이다

    public override void Init(UIManager uiManager)
    {
        base.Init(uiManager);
        bestFlappyScoreText = transform.Find("EnterMini_1/BFScoreText").GetComponent<TextMeshProUGUI>();
        thisFlappyScoreText = transform.Find("ExitMini_1/TFScoreText").GetComponent<TextMeshProUGUI>();
    }

이렇게 경로를 입력해주니 찾더라!

 

GameObject.Find 메서드는 비활성화한 오브젝트 못찾는다

transform.Find 메서드는 비활성화한 오브젝트도 찾을 수 있다. 단. 자식으로 있는 오브젝트를 찾을 때만 써야한다!

 

찾아보니

Resources.FindObjectsOfTypeAll<T>() 를 써야 자식이 아닌 비활성화 오브젝트도 찾아준다더라

 

 

 

성능상에 문제는 있지만... 편의를 위해서 GameObject.Find 메서드를 사용하면 된다

        flappyPlaneBestScoreText = transform.Find("FPBestScoreText").GetComponent<TextMeshProUGUI>();
        theStackBestScoreText = transform.Find("TSBestScoreText").GetComponent<TextMeshProUGUI>();
        theStackBestComboText = transform.Find("TSBestComboText").GetComponent<TextMeshProUGUI>();

이건 RecordUI.cs가 가진 건데.. 문제는 이 셋이 시작할 때 비활성화 되어있다는거다

그래서 계속 error가 나는데, 어쩔 수 없이

        flappyPlaneBestScoreText = GameObject.Find("FPBestScoreText").GetComponent<TextMeshProUGUI>();
        theStackBestScoreText = GameObject.Find("TSBestScoreText").GetComponent<TextMeshProUGUI>();
        theStackBestComboText = GameObject.Find("TSBestComboText").GetComponent<TextMeshProUGUI>();

Gameobject.Find를 사용하였다

우선 완성은 해야하니까

 

이렇게 해서 다른 것들도 연결을 마쳤다

이제 씬을 다시 불러와도 참조가 해제될 걱정은 없다

 

NPC를 클릭하면 RecordUI를 통해 두 게임의 최고점수를 볼 수 있게 하려고하는데

아직 NPC가 없어서 비활성화 상태다... 일단 프리팹으로 만들어놓고 나중에 쓰든지 하자

 

그리고 씬의 교체 후에 가장 먼저 실행되는게 무엇인지 알아봤는데

Awake도 Start도 아니었다

        // 메인 플레이어와 업데이트를 같이 쓰기 때문에.. 트리거 체크를 여기서 한다
        // 물고기, 햄버거 중에 어느것인지도 확인해야한다
        if (UIManager.Instance.isFishTriggered && Input.anyKeyDown)
        {
            UIManager.Instance.isFishTriggered = false; // 해제해주고 씬 교체
            SceneManager.LoadScene("FlappyPlane");
            /// 씬에 들어오기 전에 아래를 실행한다
            Debug.Log("BaseController");
        }
        else if (UIManager.Instance.isHamburgerTriggered && Input.anyKeyDown)
        {
            UIManager.Instance.isHamburgerTriggered = false; // 해제해주고 씬 교체
            SceneManager.LoadScene("TheStack");
            /// 씬에 들어오기 전에 아래를 실행한다
            Debug.Log("BaseController");
        }

LoadScene 아랫줄이 가장 먼저 실행된다

 

난 지금까지 LoadScene호출하면 그 안으로 들어가는 줄 알았는데

해당 프레임을 먼저 다 끝내고 씬을 바꾸는 것 같다

그래서 활성화 시점을 잘 정할 수 있었다

 

 

문제가 하나 더 생겼다

DontDestroyOnLoad 로 매니저들을 남겨두더라도

남은 것들의 참조가 해제되는건 알고 있었다

그러면, 다시 연결하면 된다고 생각했지만

비활성화된 저 UI들을 연결할 수가 없다...

 

 

방법이 없다...

 

어쩔 수 없다

DontDestroyOnLoad 하지 않는다

각각 매니저를 따로 선언한다...

 

그대신 점수와 콤보 만을 저장하는 DataManager를 만들어서 그걸 DontDestroyOnLoad 한다..

 

오히려 이렇게 하니까 문제가 해결됐다

 

각각의 매니저를 나누니까 

변수도 적게 가지고 있어서 참조 해제와 같은 것을 걱정할 필요가 없었다

각각 씬에 있는 것들은 씬이 로드될 때 검색해서 참조로 연결해서 해결했다