이번에 프로젝트 작업 중, 문득 Layout Group 기능을 다루다가 Editor에서 실행 없이 작동하는 기능은 어떻게 만들까하고 고민하게 되어서 공부해 보았다.
주로 인스펙터 값을 수정하거나 프로젝트 구조가 바뀔 때 호출.
OnValidate(): 인스펙터에서 값을 수정하거나 스크립트가 다시 로드될 때 호출. 레이아웃 갱신이나 값의 유효성 검사(예: 음수 방지)에 주로 사용.
Reset(): 인스펙터에서 [Reset] 메뉴를 누르거나, 컴포넌트를 처음 추가할 때 호출. 기본값을 설정하기에 가장 좋은 곳.
[ExecuteAlways] / [ExecuteInEditMode]: 클래스 상단에 붙이면 Update나 OnGUI 같은 함수들이 게임을 실행하지 않아도 에디터 모드에서 계속 실행.
오브젝트들 간의 부모-자식 관계나 순서가 바뀔 때 호출.
OnTransformChildrenChanged(): 자식 오브젝트가 추가되거나 삭제될 때 호출.
(자식을 추가하는 코드를 작성하게 된다면, 무한 루프 문제가 발생할 위험이 있음.)
OnTransformParentChanged(): 내 부모 오브젝트가 바뀌었을 때 호출.
OnRectTransformDimensionsChange(): UI 요소인 RectTransform의 크기나 피벗, 앵커가 바뀔 때 호출. 화면 해상도 대응이나 UI 리사이징 처리에 필수적.
오브젝트가 켜지거나 꺼지는 시점을 잡을 때 유용.
OnEnable(): 오브젝트나 컴포넌트가 활성화될 때마다 호출.
OnDisable(): 오브젝트가 비활성화될 때 호출.
OnDestroy(): 오브젝트가 완전히 파괴될 때 호출.
라이프사이클에서 많이 공부한 부분이다. [ExecuteAlways] 결합하면 Editor에서 실행 없이 작동한다.
| 분류 | 함수 및 속성 | 호출 시점 (Trigger) | 주요 용도 |
|---|---|---|---|
| 에디터 제어 | OnValidate() | 인스펙터 값 변경, 스크립트 로드 시 | 데이터 유효성 검사, 에디터 내 실시간 수치 반영 |
| ^ | Reset() | 컴포넌트 최초 추가, [Reset] 클릭 시 | 컴포넌트 초기화 및 기본값 설정 |
| ^ | [ExecuteAlways] | 상시 (게임 실행 여부 무관) | 에디터 모드에서 Update 등 라이프사이클 함수 실행 |
| 구조 변화 | OnTransformChildrenChanged() | 자식 오브젝트 추가, 삭제, 복사 시 | 자식 리스트 갱신, 카드 레이아웃 재정렬 |
| ^ | OnTransformParentChanged() | 부모 오브젝트가 변경되었을 때 | 부모 참조 갱신 및 계층 구조 변화 대응 |
| ^ | OnRectTransformDimensionsChange() | UI 크기, 피벗, 앵커 변경 시 | 해상도 대응, 가변 UI 리사이징 |
| 라이프사이클 | OnEnable() / OnDisable() | 오브젝트 활성화 또는 비활성화 시 | 이벤트 구독/해제, 활성 상태에 따른 레이아웃 갱신 |
| ^ | OnDestroy() | 오브젝트가 완전히 파괴될 때 | 메모리 해제 및 참조 정리 |
| 참고 게임(카제나) |
|---|
![]() |
| 테스트 코드 |
|---|
![]() |
![]() |
[ExecuteAlways] : 에디터를 실행하지 않아도 결과를 보고 싶어서 추가.
OnValidate() : 직렬화한 값이 변화됨에 따라 작동하도록 추가.
OnTransformChildrenChanged() : Layout Group과 같은 기능을 원하기 때문에 자식 오브젝트 수정에 따라 변화하도록.
DelayedAlign() : 이상하게 갑자기 코루틴을 사용했는데,
이건 자식 오브젝트가 추가될 때, 업데이트가 빠르게되어서 마지막 이미지와 그 전 이미지가 같은 위치에 배치되는 버그가 있어서 한 프레임 뒤 작동하도록 하였다.
AlignCards() : 핵심 기능이다. 솔직히 계산하는거 귀찮아서 AI 때렸다.
| 테스트 |
|---|
![]() |