인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

몽몽이 바보다옹~님의 프로필 이미지
몽몽이 바보다옹~

작성한 질문수

[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진

UI Manager #1

UI_Button 클론이 무한생성

해결된 질문

작성

·

238

·

수정됨

0

 

UI_Button 클론이 무한생성됩니다.



public class Test : MonoBehaviour
{
    GameObject er;


    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Managers.UI.ShowPopupUI<UI_Button>();
        }
    }
}

아래 코드로 문제가 있어서 화면을 클릭했을 때만 팝업이 뜨도록 위의 코드로 Test 스크립트를 일부 바꿔 봤습니다.

그러고나서 보니까

public static UIManager UI{get{return instance._ui;}} 이 지점에서 계속 다시 Test 파일의

if (Input.GetMouseButtonDown(0)) { Managers.UI.ShowPopupUI<UI_Button>(); }

이 부분으로 가는 것 같습니다. 늘어나는 갯수로 처음엔 한번 클릭했을 때는 한번으로 잘 늘어나는데 그 다음엔 2개가 생기고 그 다음엔 5개..? 규칙을 알 수 없게 늘어납니다

저 요즘 질문 너무 많이하죠..ㅜㅜ 그치만 미워하지 말아주세요 다 기본 3시간은 고민고민하며 노려보다가 보내는거긴해유..하핳..

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

public class Test : MonoBehaviour
{
    GameObject er ;
    void Start()
    {
        Managers.UI.ShowPopupUI<UI_Button>();
    }

    void Update()
    {
        
    }
}

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

public class ResourceManager
{
    public T Load<T>(string path) where T:Object
    {
        return Resources.Load<T>(path);

    }
    public GameObject Instantiate(string path, Transform parent = null)
    {
        GameObject prefab = Load<GameObject>($"Prefabs/{path}");
        if (prefab == null)
        {
            Debug.Log($"Failed to load prefab : {path}");
            return null;
        }
        return Object.Instantiate(prefab, parent);//Object붙이는 이유는 리소스메니저에 있는 Instantiate를 또 호출하려고 할까봐.
    }
    public void Destroy(GameObject go)
    {
        if(go == null)
            return;
        
        Object.Destroy(go);

    }
}


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

public class Managers : MonoBehaviour

{
    static Managers s_Instance; //유일성이 보장된다
    static Managers instance { get { Init(); return s_Instance; } } // 유일한 매니저를 갖고온다
    
    ResourceManager _resource = new ResourceManager();
    UIManager _ui = new UIManager();

    public static UIManager UI{get{return instance._ui;}}
    public static ResourceManager Resource{get{return instance._resource;}}
    // Start is called before the first frame update

    void Start()

    {

        Init();
        

    }

    // Update is called once per frame

    void Update()

    {
    }

    static void Init()

    {

        if (s_Instance == null)

        {

            GameObject go = GameObject.Find("@Managers");

            if (go == null)

            {

                go = new GameObject { name = "@Managers" };

                go.AddComponent<Managers>();

            }

            DontDestroyOnLoad(go);

            s_Instance = go.GetComponent<Managers>();

        }

    }



}using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager
{
    
    int _order = 0;
    //팝업 목록을 들고있어야함. 스택 구조으로 관리하기 가장 마지막에 띄운 팝업이 가장 먼저 삭제돼야하니까.
    Stack<UI_Popup> _popupStack = new Stack<UI_Popup>();
    public T ShowPopupUI<T>(string name = null) where T : UI_Popup//T에는 UI버튼이라는 스크립트를 건네고 name에는 팝업프리펩을 건네줄거임.
    {
        if(string.IsNullOrEmpty(name))//이름이 비어있으면 T타입의 이름과 똑같은걸로 넣겠다.
            name = typeof(T).Name;

        GameObject go = Managers.Resource.Instantiate($"UI/Popup/{name}");
        T popup = Util.GetOrAddComponent<T>(go);
        _popupStack.Push(popup);
        return popup;
    }

    public void ClosePopupUI()
    {
        if (_popupStack.Count == 0) //stack을 건드릴 떈 항상 카운트를 체크하는걸 습관화하기
            return;

        UI_Popup popup =  _popupStack.Pop();
        Managers.Resource.Destroy(popup.gameObject);
        popup = null;

        _order--;
    }

}



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

public class Util
{
    public static T GetOrAddComponent<T>(GameObject go) where T : UnityEngine.Component
    {
        T component = go.GetComponent<T>();
        if (component == null)
            component = go.AddComponent<T>();
        return component;
    }
    public static GameObject FindChild(GameObject go, string name = null, bool recursive = false)

    {

        Transform transform = FindChild<Transform>(go, name, recursive);//<Transform>을 사용하면 FindChild 메서드가 호출될 때 해당 메서드는 Transform 타입의 자식을 찾도록 약속됩니다. 이는 제네릭을 사용하여 메서드를 특정 타입에 제한하는 방법 중 하나입니다.

        if (transform == null)
            return null;

        return transform.gameObject;

    }
    public static T FindChild<T>(GameObject go, string name = null, bool recursive = false) where T : UnityEngine.Object
    {
        if (go == null)
            return null;

        if (recursive == false)
        {
            for (int i = 0; i < go.transform.childCount; i++)
            {
                Transform childTransform = go.transform.GetChild(i);

                if (string.IsNullOrEmpty(name) || childTransform.name == name)
                {
                    T component = childTransform.GetComponent<T>();
                    if (component != null)
                        return component;
                }
            }
        }
        else
        {
            foreach (T component in go.GetComponentsInChildren<T>(true))
            {
                if (string.IsNullOrEmpty(name) || component.name == name)
                    return component;
            }
        }

        return null;
    }
}

답변 2

0

Rookiss님의 프로필 이미지
Rookiss
지식공유자

image
일단 가장 인접한 코드를 다운받아 다른게 없는지 비교해보세요.
사실 질문하신 내용만 보고서는 저도 알 수가 없습니다.
코드와 별개로 GameObject에 어떻게 Component를 붙였는지 또한 관건이기 때문입니다.
요즘 정말 시간이 바빠서 일일히 코드를 봐드릴 수가 없는데요.

문제가 일어날 때 유용한 방법은
- 책 or 강의 코드를 부분적으로 복붙해가며 다른 부분 있는지 범인 색출
- 디버깅 (로그 찍거나, breakpoint 걸어서 멈춰서 보기)
- 코드 분석 (무한 헤딩)

등이 있는데요. 처음엔 고통스럽겠지만
어차피 프로그래머의 업무중에 50% 이상은 버그 찾는 것이라
익숙해지셔야 합니다.

0

안녕하세요, 인프런 AI 인턴입니다.

해당 문제와 관련하여 이전에 다른 수강생이 비슷한 문제를 제기한 사례가 있어 유사한 경우를 찾았습니다. 아래 링크를 통해 비슷한 문제에 대한 강사님의 답변을 참고해보시면 도움이 될 것 같습니다.

도움이 되셨길 바라며, 질문&답변 게시판을 통해 추가적인 질문이 있으시면 언제든지 올려 주시기 바랍니다.

몽몽이 바보다옹~님의 프로필 이미지
몽몽이 바보다옹~

작성한 질문수

질문하기