유니티 개발을 생업으로 삼는 사람이라면 들어봤을 Odin Inspector.

게임 개발을 깔끔하고 쾌적하게 해준다는 장점이 있다.


24b0d121e09c28a8699fe8b115ef046c63f92e4c



하지만 55달러, 할인하면 약 27달러의 가격이다.


기능 전부 다 쓸것도 아니고, 공부도 할겸 어트리뷰트를 직접 만들어보기로 했다.


---



24b0d121e09c28a8699fe8b115ef046a786aefcb


오랜만에 리팩토링이랑 최적화하고 기능좀 추가하려고 켰는데 아주 가관이다.


프로퍼티의 수가 너무많아 Header 만으로는 정리가 되지 않는다.


Inspector 창에서 Foldout을 할 수 있으면 좋을것 같다.



우선 Attribute를 만들자.


24b0d121e09c28a8699fe8b115ef046c61f82f47



이렇게 PropertyAttribute 를 상속받고 이름의 끝에 Attribute를 붙이면 완성이다.


24b0d121e09c28a8699fe8b115ef046541a9f5


이런식으로 자동완성 창에서 볼 수 있게 된다.



이제 Attribute의 기능을 만들자


기능을 만드는 방식은 크게 두 가지이다.


1. PropertyDrawer 를 상속받아서 각 Property 를 OnGUI 단위로 그리기

2. Editor를 상속받아서 특정 스크립트의 InspectorGUI 그리기



1. PropertyDrawer 로 그리기 (비추천)



24b0d121e09c28a8699fe8b115ef046f5d499e9a


FoldoutGroup과 Foldable 어트리뷰트를 통해 다같이 Fold로 묶는게 목적이다.


PropertyAttribute는 특정 어트리뷰트가 붙어있을때에만 실행되므로 영향을 끼칠 변수에 전부 붙여야한다.



24b0d121e09c28a8699fe8b115ef046f5b4e9f9e


CustomPropertyDrawer -> 이 어트리뷰트 보이면 아래 override 함수들이 실행됨


foldoutStates 는 각 헤더의 fold가 열렸는지 상태 확인하려고, headerDict 는 override하는 두  함수간의 실행주기가 달라서 property-header 를 Entry로 저장해둠.

특히, 변수하나 그릴때마다 새로운 클래스가 만들어지기 때문에 상태를 저장하기 위해서는 static으로 둬야함.



24b0d121e09c28a8699fe8b115ef0468e5aaeabd


에디터를 다루면 자주봤을 GetPropertyHeight 함수임.


여기서 리턴하는 값으로 해당 프로퍼티가 사용할 수 있는 높이가 정해짐


-- 요약


헤더 fold가 열려있는 경우 : 

    FoldoutGroup -> singleLineHeight + PropertyHeight

    Foldable        -> PropertyHeight 

헤더 fold가 닫혀있는 경우 :
    FoldoutGroup -> singleLineHeight (Foldout 그려야됨)

    Foldable        -> 0



똑같은 논리로 OnGUI 함수를 만들고 필요한 곳에 필요한걸 그리면됨



24b0d121e09c28a8699fe8b115ef046b65679632



대충 오류도 고치고 하면 완성이 되지만, 이 방법은 큰 문제가 있음



24b0d121e09c28a8699fe8b115ef046c65f6294b


GetPropertyHeight에서 0을 반환하고 아무것도 안그려도 자동으로 프로퍼티 간에 패딩을 넣어준다는 거임;


이 값은 프로퍼티당 2px 로 EditorGUIUtility 의 standardVerticalSpacing 값과 유사함


24b0d121e09c28a8699fe8b115ef046a7e69ef


당연하게도 이렇게 중요한건 읽기전용이므로 더이상 할 수 있는게 없음.


GetProperty로 -2를 반환하건 OnGUI에서 2px 위쪽에 뭘 그리건 해결되지 않음




2. Editor 로 그리기


이건 그냥 스크립트의 InspectorGUI를 처음부터 하나씩 그리는거임

여기서는 Monobehaviour 의 Inspector를 그려야함.



24b0d121e09c28a8699fe8b115ef046f584a989d


우선 Attribute를 이런식으로 바꿈



24b0d121e09c28a8699fe8b115ef046f584c989c


CustomEditor를 선언하고 뒤에 true를 붙여줘야 Monobehaviour 상속받은 애들까지 처리해줌


foldoutStates 는 위에거랑 하는일이 똑같고, propertyDataList는 각 프로퍼티의 정보와 FoldoutGroup 정보를 페어로 담아둠


24b0d121e09c28a8699fe8b115ef046c62f92d4c


에디터와 스크립트의 상태를 동기화시키기 위해서, 

맨처음에 Update로 스크립트의 값들을 받아오고, 다 처리를 한 후에 Apply~ 로 스크립트에 반영함.

잘 모르겠으면 int main(void) 처럼 그냥 적으면됨.



24b0d121e09c28a8699fe8b115ef046b6c6f9731



24b0d121e09c28a8699fe8b115ef046f5f4e9b9c



Properties 를 보고 propertyDataList에 채워넣는 함수임.

단순히 prop.NextVisible 로 순회하면서 채우면 될 줄 알았지만, 아쉽게도 Vector3 의 NextVisible은 Vector3.x, Vector3.y ... 이렇게 멤버를 다 순회함


밑쪽의 부분이 그거 예외처리 하드코딩 해둔거고, 나중에 고치긴 해야될듯



24b0d121e09c28a8699fe8b115ef046f564f9c9f


Property를 그리는 부분임.

data.Attribute는 FoldoutGroupAttribute 말하는거라, 그거 없으면 그냥 그리고, 있으면 그룹 단위로 그려줌. 


이렇게 하고 실행해보면



24b0d121e09c28a8699fe8b115ef046c63f0214c


24b0d121e09c28a8699fe8b115ef046c66f02e4c


잘 되는걸 확인할 수 있음.

뭔가 Script 에 Readonly 가 사라진것같긴한데, 별로 상관없을듯

이제 저 밋밋한 Foldout 을 꾸미기만 하면됨


24b0d121e09c28a8699fe8b115ef046f58459f9c



24b0d121e09c28a8699fe8b115ef046c62f22a4798



굿