Unity 최종 프로젝트 - 19 (Behavior Tree Repactoring 이유/기술적 고민/개선 예정 사항)

이준호·2024년 2월 9일
0

📌 Unity 최종 프로젝트



📌 리팩토링의 이유

  • Action을 각 클래스로 나누지 않고 생성자와 Func를 통해서 한 스크립트에서 구조를 짜고 행동을 구현하다 보니 점점 규모가 커지며 코드가 매우 길어지고 각 액션들의 확인이 매우 불편해졌습니다.

  • 그리하여 Action을 각각의 클래스로 나눠 분할을 해봤지는데 코드의 가독성이 훨씬 좋아졌습니다. 하지만 그래도 행동트리의 구조가 어떤식으로 작동해서 돌고있는지 내부적인 확인은 아직 어려움이 있었습니다.

  • 최상위 Node를 Scriptable Object로 만들어 중복 데이터를 막고, 하위 노드들이 Node를 상속받아 SO로 만들어 인스펙터 창에서 해당 트리가 어떤 노드들을 가지고있는지 확인할 수 있게 하였는데 노드의 구조상 일열로 배치된 것만 보이니 어떤 노드가 들어갔는지는 알아도 어떻게 작동되는지는 확인이 어려운 점이 남아있었습니다.

  • 그리하여 UI Builder를 이용한 GraphView Editor를 만들어 내부적인 코드 구조를 몰라도 각 마우스와 버튼의 상호작용을 통해 쉽게 BT를 구성할 수 있고, 시각적으로도 한눈에 어떻게 구성되고 어떻게 흘러가는지 확인이 가능하여 유지보수성과 가독성이 매우 향상되었습니다.

  • 또한 SO작업을 하며 최상위 Node 클래스에서 FSM의 구조와 비슷한 Start, Update, Stop을 만들어 Start -> Update -> Stop 순으로 작동하고, 노드가 최초에 Start를 한번 실행하고 Running을 반환하면 다음 순회 때 Start는 실행되지 않게 하였습니다. 이렇게 바꾸게된 이유는 랜덤 좌표를 찍어서 이동하면 그 좌표에 도달할 때 까지는 다시 랜덤좌표가 찍히면 안되는데 이 방식을 쓰기 전에는 Bool값을 사용하여 여러곳에서 처리를 막아줘야 했습니다. 하지만 Start를 활용하여 유지보수성이 향상시키기 위해 변경하였습니다.












📌 리팩토링의 이유 (핵심 요약)

  • Inspetor창에서 Enemy 행동트리의 구조가 일렬로 표현되어 내부적인 흐름을 파악하기 어려워 불편하였다.
    그래서 Graph View와 UI Builder를 사용하여, 구조를 시각적으로 확인이 가능한 Editor를 제작하여 내부 노드 구조가 어떤식으로 흘러가는지 쉽게 파악이 가능할 수 있도록 적용하여 가독성 향상되고 개발 시간을 단축하였다.

  • Scriptable Object를 이용한 클래스와 데이터 관리로, 클래스의 중복을 막고 각각의 액션 클래스를 탈부착이 가능하게 하여 유지보수성이 향상되었다.

  • 각각의 액션 클래스들이 독립적이게 만들고, 연결시에는 유기적으로 작동하게 하여 체계적인 관리가 가능하게 만들었다.

  • Behavior Tree에 FSM의 순환 요소를 결합하여 노드를 순회할 때 필요한 일회성 값들을 보다 쉽게 관리하고 수정이 가능하도록 만들었다.












📌 생성자 vs Instantiate

생성자

  • Scriptable Object를 이용하여 행동트리를 만들면, 구조를 에셋으로 저장하고 재사용이 가능하다.

  • 또한 유니티 에디터에서 직접 행동트리를 구성하고 수정하는 것이 가능하므로, 디버깅과 유지 보수가 용이하다.

  • 또한 각 노드를 복제(Instantiate)하여 사용하면 런타임 도중에 노드의 상태를 독립적으로 변경할 수 있어, 동적인 행동 구현이 용이하다.

  • 구조의 변경이 매우 간단해진다.

Instantiate

  • 생성자를 이용한 방법은 코드를 통해 행동트리를 직접 생성하고 관리해야 하므로, 행동트리의 구조를 보거나 수정하는 것이 어렵고 디버깅이 복잡할 수 있다.

  • 또한 행동트리의 구조를 코드로 직접 작성해야 하므로, 행동트리의 구조를 바꾸거나 내부 행동을 바꾸려면 직접 코드를 바꿔줘야한다.

  • 구조를 변경하려면 직접 스크립트상에서 고쳐줘야한다.












📌 메모리 개선 예정

  • 생성자를 사용하는것 보다, SO를 사용해서 Instantiate를 사용해 복제하면 더 많은 비용이 발생할 수 있다.

  • 하지만, 노드의 수가 적거나 복제가 자주 발생하지 않는다면 Instantiate를 사용해도 무시할 수 있을정도로 작다.

  • 또한, 비동기 로딩을 이용해 미리 복제하여 준비해두면 부하를 많이 줄일 수 있다.

  • 하지만 Instantiate로 복제된 객체들을 제거할 때도 생각해야 한다. 어떻게 제거해야 좋을지 생각해 볼 필요가 있다.

  • 그래서 추후, So방식의 구현이 완료가 되면 생성자와 Instantiate를 이용한 방식 두 방식의 메모리 비교를 해서 비교할 예정이다. (필수)

profile
No Easy Day

0개의 댓글