팀 내용 자체 보다는 만났던 버그와 해결, 그리고 무엇을 항상 놓치는지에 대해 서술한다.
당연하지만 자칫 놓치기 쉬운 내용이다.
몬스터를 생성하기 위해, 그리고 관리의 편의성으로 대부분의 계층구조내 오브젝트를 프리팹으로 전환하여 개발 중이다.
특히 몬스터는 이미 놓여있는 것이 아니라 필요시 생성해야하기 때문에 다른 오브젝트와의 상호작용에 필요한 내용을 잘 가져와야 한다.
플레이어와의 상호작용을 위해 컴포넌트간 연결을 생각 없이 프리팹으로만 연결 하였다가 큰 참사를 보게 되었다.
버그 내용은 이렇다.
적을 처치하면 플레이어는 경험치를 얻는다. 플레이어의 경험치 및 레벨을 담당하는 컴포넌트(이하 PlayerLevel)가 별도로 있는데, 이것을 적 프리팹에 연결하여 값을 전달하도록 하였다. PlayerLevel 에서 해당 경험치가 변경되면 UI 가 변동하도록 경험치에 대한 Event 를 선언해 주었다. 그리고 테스트를 하였는데, 값도 변하고 잘 값도 넘겨받았는데 Event 도 실행 된 것 같은데 UI 가 변경되지 않았다. 도데체 왜 그런 것일까?
Evnet.GetHashCode()
이 함수는 이번 버그를 찾는데 큰 공로를 세웠다. UI 에서 받아온 Event 와 실제 선언된 Event 는 서로 다른 Hash 값을 갖고 있었다. 즉, 서로 다른 Event 였던 것이다!
사실 이 부분은 Gemini 와 같이 확인 해보았다. (너무.. 시간이 오래걸려서..ㅠㅠ)
여기서 난 프리팹에 직접 연결해준 Component 에 초점을 맞추었고, 확인 결과 Player 프리팹을 연결했다는 것을 찾게 되었다. 우리가 제어할 Player 는 씬에 이미 나와있는 오브젝트니 그것을 연결해 주어야 한다.
프리팹 내 Component 는 계층구조에 있는 것을 직접 연결 할 수는 없다. 따라서
GameObject.FindWithTag("Player").GetComponent<PlayerLevel>();
이러한 코드를 이용하여 찾아주는 방식을 채택하였다.
물론 위 코드는 코스트가 상당히 높기 때문에 Awake에서 한번만 수행된다.
개발 단계에서 무기의 Status 를 하나의 Class 에 담아 이를 상속하는 상세 무기를 구현하기 위해 준비하였다.
각 무기에는 탄수가 있으며 이는 UI 에 이벤트를 이용하여 연결해 주었다.
여기서도 문제가 터졌는데......후...😅
부모 클래스에서 선언되지 않은 이벤트를 자식에서 선언하면 이상하게 코드가 꼬였다 ㅡㅡ
궁극적으로는 위에 이슈처럼 서로 다른 이벤트를 바라보고 있는 것이었는데, 이해가 잘 되지 않아
어.쩔.수.없.이. Gemini 에게 문의 한 결과
결론적으로는 "참조타입 (Call by Reference)"에 의한 이슈 였다.
뭐.. 직렬화 시점이 이렇고 저렇고 이야기가 나오긴 했는데 현재 나에게는 잘 이해가 가지 않는 부분이다. (나중에 강사님에게 좀 물어봐야겠다)
즉, 부모 클래스에서 선언은 했지만 이직 new 하지 않은 상태에서 자식 클래스에서 new 로 선언하고 부모 클래스로 upcast 된 객체를 갖고 무언가를 진행하면 참조된 값이 다르게 된다는 이야기... 로 보인다.
아직 프로젝트 중이라 이 부분은 좀 애매해서, 프로젝트 끝나고 별도로 간단히 테스트를 해보아야 할 것 같다.