• 카테고리

    질문 & 답변
  • 세부 분야

    게임 프로그래밍

  • 해결 여부

    해결됨

UI_Button 클론이 무한생성

23.12.22 18:53 작성 23.12.22 19:10 수정 조회수 145

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

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

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

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

0

인프런 AI 인턴님의 프로필

인프런 AI 인턴

2023.12.22

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

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

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