현재 Scene이 Null이 발생하는 문제

  • CurrentScene에 IntroScene을 할당하고 CurrentScene 이 IntroScene 인것을 확인
protected override bool Initialized()  
{  
    if (!base.Initialized()) return false;  
    // TODO : 인트로 씬 실행시 Context 작성   
    CurrentScene = Label.IntroScene;  
    LoadResource();  
    return true;  
}  
  
private void LoadResource()  
{  
    if (Main.Resource.LoadIntro)  
    {  
        // TODO : 로드가 되어있다면, 추가적인 초기화 필요  
        Main.UI.SetSceneUI<Intro_UI>();  
    }  
    else  
    {  
        string sceneType = CurrentScene.ToString();  
        Debug.Log($"Current Scene : {sceneType}");  
        Main.Resource.AllLoadAsync<UnityEngine.Object>($"{sceneType}", (key, count, totalCount) =>  
        {  
            Debug.Log($"[{sceneType}] Load asset {key} ({count}/{totalCount})");  
            if (count < totalCount) return;  
            Main.Resource.LoadIntro = true;  
            // TODO : 추가적인 초기화 필요  
            Main.UI.SetSceneUI<Intro_UI>();  
        });    
	}
}

  • 하지만 Popup을 열어 Time Scale을 확인하려고 하는데 Null 이 발생하는 문제
private void SetTimeScale()  
{  
    Debug.Log($"UI_Manager - CurrentScene : {Main.Scene.CurrentScene}");  
    if (Main.Scene.CurrentScene != Label.GameScene)  
    {        
	    Time.timeScale = 1;  
        return;  
    }    
    Time.timeScale = _popupOrder.Count > 0 ? 0 : 1;  
}

문제확인

  • private 로 선언된 변수를 public으로 변화시켜 인스펙서에서 실시간으로 해당 변수의 변화를 확인 시도
public Label _sceneLabel;  

public Label CurrentScene  
{  
    get  
    {  
        Debug.Log($"Get Label {_sceneLabel.ToString()}");  
        return _sceneLabel;  
    }    
    
    set  
    {  
        _sceneLabel = value;  
        Debug.Log($"Set Label {_sceneLabel.ToString()}");  
    }
}

  • IntroScene에서는 정상적으로 할당이 되나, Singleton 에서 Scene이 정상적으로 할당 되지 않는 문제 확인

  • 이것은 Main 스크립트에서 초기화가 제대로 적용되지 않는 것으로 보임

#region Fields  
  
private readonly UI_Manager _ui = new();  
private readonly ResourceManager _resource = new();  
private readonly PlayerController _playerControl = new();  
private readonly DataManager _data = new();  
public BaseScene _scene;   
#endregion  
  
#region Properties  
  
public static UI_Manager UI => Instance._ui;  
public static ResourceManager Resource => Instance._resource;  
public static BaseScene Scene => Instance._scene;  
  
#endregion

문제 해결

  • Scene 할당시 Main의 씬 객체에 할당
public static void SetCurrentScene(BaseScene scene, Label sceneLabel)  
{  
    Instance._scene = scene;  
    Instance._scene.CurrentScene = sceneLabel;  
}
  • 각 씬 호출 마다 해당 메서드를 실행
public class IntroScene : BaseScene  
{  
    protected override bool Initialized()  
    {        
	    if (!base.Initialized()) return false;  
        // TODO : 인트로 씬 실행시 Context 작성   
		Main.SetCurrentScene(this, Label.IntroScene);  
        LoadResource();  
        return true;  
    }
}

이벤트 실행 문제

  • 이벤트가 마지막 할당한 Key 값만 적용되어 모든 Click이 한가지 동작만 되는 문제
protected override bool Initialized()  
{  
    if (!base.Initialized()) return false;  
	SetButton(typeof(Buttons));  
	GetButton((int)Buttons.StartBtn).gameObject.SetEvent(UIEventType.Click, StartGame);  
    GetButton((int)Buttons.ContinueBtn).gameObject.SetEvent(UIEventType.Click,StartGame);  
    GetButton((int)Buttons.OptionBtn).gameObject.SetEvent(UIEventType.Click,OptionOpen);  
    GetButton((int)Buttons.ExitBtn).gameObject.SetEvent(UIEventType.Click, ShutdownGame);  
    return true;  
}
public enum UIEventType  
{  
    Click, PointerEnter, PointerExit  
}  

public class UI_EventHandler : MonoBehaviour, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler  
{  
    private static Dictionary<UIEventType, Action<PointerEventData>> EventHandlers = new();  
  
    private void InvokeEventAction(UIEventType eventType, PointerEventData eventData)  
    {        
	    if (EventHandlers.TryGetValue(eventType, out var action)) action?.Invoke(eventData);  
    }  
    
    public void BindEvent(UIEventType eventType, Action<PointerEventData> action)  
    {        
	    EventHandlers[eventType] = action;  
    }  
    
    public void UnbindEvent(UIEventType eventType)  
    {        
	    if (EventHandlers.ContainsKey(eventType))  
        {  
            EventHandlers.Remove(eventType);  
        }  
    }  
  
    public void OnPointerClick(PointerEventData eventData) => InvokeEventAction(Click, eventData);  
    public void OnPointerEnter(PointerEventData eventData) => InvokeEventAction(PointerEnter, eventData);  
    public void OnPointerExit(PointerEventData eventData) => InvokeEventAction(PointerExit, eventData);  
  
    private void OnDestroy()  
    {        
	    EventHandlers.Clear();  
    }
}
  • 각 오브젝트에 해당 클래스를 이벤트 오브젝트마다 할당하여 사용
  • 그런데 왜 모든 오브젝트의 이벤트가 같은 기능을 작동하는지 문제 파악 필요
protected override bool Initialized()  
{  
    if (!base.Initialized()) return false;  
    SetButton(typeof(Buttons));  
    GetButton((int)Buttons.StartBtn).gameObject.SetEvent(UIEventType.Click, StartGame);  
    GetButton((int)Buttons.ContinueBtn).gameObject.SetEvent(UIEventType.Click,StartGame);  
    GetButton((int)Buttons.OptionBtn).gameObject.SetEvent(UIEventType.Click,OptionOpen);  
    GetButton((int)Buttons.ExitBtn).gameObject.SetEvent(UIEventType.Click, ShutdownGame);  
    return true;  
}  
  
private void OptionOpen(PointerEventData obj)  
{  
    Main.UI.OpenPopup<Option_Popup>();  
}  
  
private void StartGame(PointerEventData obj)  
{  
    SceneUtility.LoadScene("GameScene");  
}  
  
private void ShutdownGame(PointerEventData obj)  
{  
    Application.Quit();  
}
  • 어떠한 버튼을 눌러도 마지막에 이벤트 등록된 ShutDownGame이 실행 됨

  • OptionBtn을 실행 했을 때 Intro_UI.ShutdownGame() 이 실행되는 Debug 모습

문제 해결

  • 간단한 문제 였지만 찾는데 오래 걸렸다
  • UI_EventHandler 의 키를 저장하는 Dictionary 가 static으로 선언
  • 그로인해 모든 이벤트가 마지막 세팅된 이벤트를 따가가게 되는 현상