# Unity 개발 지침 (UI Toolkit · MVVM · 성능 · Nullable) 본 지침은 Unity UI Toolkit 기반 프로젝트의 아키텍처, 성능, 코드 품질을 일관되게 유지하기 위한 규칙입니다. 프로젝트 스타일: `#nullable enable`, UniTask, DOTween, 한국어 주석 --- ## 0) 작업 진행 규칙 **⚠️ 최우선 규칙: 임의로 진행하지 않고, 반드시 사용자에게 확인 후 진행합니다.** - 코드 수정, 파일 생성/삭제, 리팩토링 등 **모든 변경 작업은 사전에 계획을 설명하고 승인을 받은 후** 진행합니다. - 요구사항이 모호하거나 여러 접근 방식이 가능한 경우, **추측하지 말고 질문**합니다. - 버그 수정이라도 원인 분석 결과를 먼저 공유하고, 수정 방향에 대해 합의 후 코드를 변경합니다. - 단순한 오타 수정, 한 줄 변경 등 **명백하고 사소한 작업**만 즉시 진행할 수 있습니다. --- ## 1) 핵심 원칙 ### UI 프레임워크 - **UI Toolkit(UIElements) 필수 사용**. uGUI(Canvas 기반)는 레거시로 취급합니다. - UXML(구조)과 USS(스타일)를 분리하고, C# 코드에서 인라인 스타일 지정을 지양합니다. ### 이벤트 콜백 등록 규칙 **⚠️ 중요: `RegisterValueChangedCallback` 대신 `RegisterCallback>`를 사용합니다.** `RegisterValueChangedCallback`은 확장 메서드로 `UnregisterCallback`과 대칭이 맞지 않아 이벤트 해제가 어렵습니다. ```csharp // ❌ 잘못된 예: 해제가 어려운 방식 field.RegisterValueChangedCallback(OnValueChanged); // field.UnregisterValueChangedCallback(OnValueChanged); // 이런 메서드 없음! // ✅ 올바른 예: 대칭적인 등록/해제 field.RegisterCallback>(OnValueChanged); field.UnregisterCallback>(OnValueChanged); private void OnValueChanged(ChangeEvent evt) { // evt.newValue, evt.previousValue 사용 } ``` | 메서드 | 권장 | 이유 | |--------|------|------| | `RegisterValueChangedCallback` | ❌ | 해제용 메서드 없음 | | `RegisterCallback>` | ✅ | `UnregisterCallback` 대칭 | ### 커스텀 VisualElement (Unity 6) Unity 6에서는 **레거시 `UxmlFactory`/`UxmlTraits` 방식을 사용하지 않고**, 소스 생성기 기반의 `[UxmlElement]`와 `[UxmlAttribute]`를 사용합니다. #### 필수 규칙 1. **클래스에 `[UxmlElement]` 어트리뷰트 추가** 2. **클래스를 `partial`로 선언** (소스 생성기 요구사항) 3. **UXML 속성은 `[UxmlAttribute]`로 케밥 케이스 소문자 명시** ```csharp // ✅ 올바른 예: Unity 6 방식 [UxmlElement] public partial class UTKCodeBlock : VisualElement { [UxmlAttribute("title")] public string Title { get; set; } [UxmlAttribute("is-enabled")] public bool IsEnabled { get; set; } [UxmlAttribute("border-width")] public int BorderWidth { get; set; } } // ❌ 잘못된 예: 레거시 방식 (사용 금지) public class UTKCodeBlock : VisualElement { public new class UxmlFactory : UxmlFactory { } public new class UxmlTraits : VisualElement.UxmlTraits { ... } } // ❌ 잘못된 예: 케밥 케이스 미사용 [UxmlAttribute] // Unity 6에서 UXML 속성 매핑 실패 public string Text { get; set; } [UxmlAttribute("Text")] // 대문자는 UXML과 불일치 public string Text { get; set; } ``` **UXML 사용 예:** ```xml ``` ### 아키텍처 (MVVM/MVC) ``` ┌─────────────┐ ┌──────────────┐ ┌─────────────┐ │ View │◄────│ ViewModel │◄────│ Model │ │ (UXML/USS) │ │ (Presenter) │ │ (Service) │ └─────────────┘ └──────────────┘ └─────────────┘ │ │ └── 이벤트 전달 ──────┘ ``` | 레이어 | 책임 | 금지 사항 | |--------|------|-----------| | **View** | 표시/레이아웃, 이벤트 라우팅 | 비즈니스 로직, 상태 보유 | | **ViewModel/Presenter** | 상태 관리, 데이터 변환, 바인딩 속성 | Unity API 직접 호출 (테스트 용이) | | **Model/Service** | 도메인 로직, 데이터 접근 | UI 참조 | - **MVVM**: UI 상태/양방향 동기화가 많을 때 - **MVC**: 입력 → 도메인 액션 → UI 반영 흐름이 단순할 때 ### 필수 규약 - 파일 선두에 `#nullable enable`, 모든 참조형에 `?` 명시 - 비동기는 `UniTask` + `CancellationToken` 사용 (`Task`/코루틴 지양) - 느슨한 결합: 인터페이스/이벤트로 연결 --- ## 2) 폴더 구조 ``` Assets/ ├── Scripts/ │ ├── {프로젝트명}/ # 프로젝트별 코드 │ │ ├── Config/ # 설정, 상수 │ │ ├── Manager/ # 매니저 클래스 │ │ ├── Command/ # Command 패턴 (Undo/Redo) │ │ └── ... │ └── UVC/ # 공통 라이브러리 ⭐ │ ├── Core/ # DI, Injector, Singleton │ ├── Data/ # DataMapper, MQTT/HTTP 통신 │ ├── Pool/ # 오브젝트 풀링 │ ├── UI/ # uGUI 컴포넌트 (Modal, Tab) │ └── UIToolkit/ # UI Toolkit 컴포넌트 ⭐ ├── Resources/ │ ├── {프로젝트명}/ # 프로젝트별 리소스 │ │ ├── Materials/ │ │ ├── Models/ │ │ └── Prefabs/ │ └── UIToolkit/ # 공통 UI 리소스 ⭐ │ ├── Common/ # 공통 스타일 (USS) │ ├── List/ # 리스트 컴포넌트 (UXML) │ ├── Modal/ # 모달 컴포넌트 (UXML) │ ├── Property/ # 속성 편집기 (UXML) │ └── Window/ # 윈도우 컴포넌트 (UXML) ├── Plugins/ # 서드파티 (Best.HTTP, DOTween 등) ├── Sample/ # 샘플 씬 └── Scenes/ # 앱 씬 ``` **현재 프로젝트:** | 폴더 | 설명 | |------|------| | `Scripts/Factory` | 스마트 팩토리 3D 시각화 (MQTT 실시간) | | `Scripts/Simulator` | Factory 시뮬레이션 버전 | | `Scripts/Studio` | 3D 씬 에디터 (Undo/Redo, Gizmo) | | `Scripts/SHI` | 조선소 공정 모달 (TreeList, Chart) | | `Scripts/NHN` | 무한 스크롤 컴포넌트 (uGUI 레거시) | > **참고**: 각 폴더에 `CLAUDE.md` 파일이 있어 모듈별 상세 가이드를 제공합니다. --- ## 3) 성능 최적화 ### VisualElement 쿼리 ```csharp // ❌ 나쁜 예: 매 프레임 쿼리 void Update() { rootVisualElement.Q