TIL - Out of Work 4일차

Amberjack·2024년 2월 15일
0

TIL

목록 보기
40/83
post-thumbnail

🛗 24.02.15 Out of Work 4일차

오늘은 사실상 팀 프로젝트 마지막 날이다. 오늘 마무리를 하고 내일 12시까지 발표자료와 시연영상, 팀 노션 정리, ReadMe 작성 등을 할 예정이다.

👨‍💻 Codekata

https://velog.io/@amberjack/C으로-풀기-서울에서-김서방-찾기

Array.FindIndex를 통해 배열에서 일치하는 인덱스의 위치를 가져올 수 있다.

🛠️ 스크립트로 Object 찾기

Inspector에서 Game Object를 찾아서 넣는 게 확실히 편하기는 하지만, 굉장히 귀찮아지고 예상치 못한 경우들이 많이 발생하는 것 같다. 점점 프로젝트를 진행할 수록 스크립트로 Object를 찾아서 넣어줄 필요성을 깨닫는 것 같다.

스크립트로 Button OnClick() 추가하기

정말 귀찮은 일 중에 하나가 Button의 OnClick()을 추가해주는 것이다. 스크립트가 변경이 된다거나 할 때마다 missing 되는 경우가 생기기 때문이다. 따라서 스크립트에서 Button을 찾아서 AddListener를 추가해주는 방식을 사용해보았다.

스킬 트리 씬에서 스킬 강화 후 테스트를 위한 스킬 사용 기능을 추가한다고 가정해보자.

우측 하단의 동그란 버튼이 스킬 트리 씬에서의 테스트용 스킬 버튼이다.

이를 위해서 스킬 버튼 코드를 작성해보자. 아래의 코드는 우리 팀 프로젝트에서 SkillManager에 작성된 스킬 버튼의 코드이다.

public void SkillButton()
{
    // 스킬 버튼 클릭 시...
}

문제는, SkillManager가 해당 씬에 없어서 발생을 했다.

SkillManager는 GameManager 밑에서 DontDestroyOnLoad가 되어 있기 때문에 StartScene에서 생성이 된다. 따라서 스킬 트리 씬에서는 하이라키창을 통해 스킬 버튼의 OnClick()에 넣어주지 못하는 상황이다.

때문에 이를 해결하기 위해 해당 스킬 트리 씬이 로드될 때, SkillManager에서 스킬 버튼을 찾아서 OnClick에 연결해주는 방식을 사용했다.

public Button skillButton;

...

public void SkillButton()
{
    // 스킬 버튼 클릭 시...
}

...

private void OnEnable()
{
    SceneManager.sceneLoaded += OnSceneLoaded;
}

void OnDisable()
{
    SceneManager.sceneLoaded -= OnSceneLoaded;
}

void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
    if (scene.buildIndex == 7)
	{
    	skillButton = GameObject.Find("SkillButton").GetComponent<Button>();
    	skillButton.onClick.AddListener(SkillButton);
	}
}

물론 하드 코딩인 것 같긴 한데... 현재 내가 생각해낼 수 있는 최선이었다.
GameObject.Find를 통해 스킬 버튼을 찾고, 그 스킬 버튼의 컴포넌트에서 Button을 찾아 연결해준다. 이후, AddListener()를 통해 OnClick()이 발생했을 경우 위의 SkillButton()이 실행되도록 작성했다.

😫 Scene 변경 시 이벤트 해제하기!

우리 팀 프로젝트는 총 5개의 스테이지로 구성이 되어 있다. 스테이지를 클리어 성공 혹은 실패할 때 결과를 띄워주는 UI가 있었다. 이 UI는 엘리베이터의 HP가 0이 될 때 발생하는 OnStageClear 이벤트, 제한 시간을 초과하면 발생하는 OnStageOver 이벤트를 구독하고 있었다.

using TMPro;
using UnityEngine;

public class ClearPopupUI : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI stageText;
    [SerializeField] private TextMeshProUGUI rewardText;
    [SerializeField] private TextMeshProUGUI headText;

    private void Start()
    {
        gameObject.SetActive(false);
        StageManager.instance.OnStageClear += StageClear;
        StageManager.instance.OnStageOver += GameOver;
    }

    private void Update()
    {
        
    }

    public void OnClickcontinueButton()
    {
        Time.timeScale = 1.0f;

        if (StageManager.instance.currentStage.NowStage == 1)
        {
            LoadingSceneController.LoadScene("Ending");
            return;
        }
        LoadingSceneController.LoadScene("SelectStage");
    }

    private void StageClear(int reward)
    {
        gameObject.SetActive(true);
        stageText.text = GameManager.instance.selectedStage.ToString();
        headText.text = "Clear!";
        rewardText.text = reward.ToString();
    }

    private void GameOver()
    {
        gameObject.SetActive(true);
        stageText.text = GameManager.instance.selectedStage.ToString();
        headText.text = "Game Over";
        rewardText.text = "0";
    }
}

Start()에서 이벤트들을 구독하고, 해당 이벤트들이 호출되면 그에 맞춰 UI창을 띄워주는 방식이었다.

게임을 실행하고 처음 스테이지를 도전할 때는 문제 없이 동작했지만, 문제는 그 이상으로 스테이지를 도전할 경우, 스테이지 종료 시 띄울 UI창이 Missing이 되는 문제가 발생했다.

구글링을 해보고 Debug.Log, 중단점을 찍어가며 문제를 찾아보려 했지만 UI는 바람처럼 사라질 뿐이었다. 골머리를 앓다가 결국 튜터님에게 들고 가서 질문을 했는데, 튜터님께서 문제를 파악해주시고 해결을 해주셨다!

원인

원인은 Start()에서 구독했던 이벤트들 때문이었다! 해당 스테이지 씬을 벗어날 때, 씬이 변경되면서 Destroy가 되는데, 이것을 간과하고 코드를 작성해서 발생한 문제였다. UI는 Destroy가 되었지만, StageManager에 등록된 이벤트들은 해제가 되지 않아서 해당 이벤트를 발생시킬 때, 이미 Destroy 된 UI에 이벤트를 뿌려주려고 하니 생긴 문제였다!

따라서 해결 방법은 UI가 Destroy 될 때, 이벤트 구독을 해제시켜주는 것이었다.

private void OnDestroy()
{
    StageManager.instance.OnStageClear -= StageClear;
    StageManager.instance.OnStageOver -= GameOver;
}

앞으로는 씬이 전환될 때 Destroy가 된다는 것을 명심해두고 코드를 작성하자!!

🛗 오늘의 회고

오늘은 팀 프로젝트를 마무리 짓는 날이었다. 팀원들이 작업한 내용을 모두 병합하여 같이 플레이해보며 QA를 진행했다. 다행히도 엄청난 문제는 발생하지 않은 것 같아 다행이다. 무난하게 팀 프로젝트를 진행할 수 있어서 기쁘다!

0개의 댓글