|
| 1 | +# 컴포넌트 분석 문서 |
| 2 | + |
| 3 | +## 개요 |
| 4 | +이 문서는 ProjectVG-Client의 핵심 컴포넌트들을 분석하고 정리한 문서입니다. Live2D 캐릭터 시스템의 입력 처리, 시선 추적, 터치 인터랙션, 그리고 시스템 관리에 대한 구조를 설명합니다. |
| 5 | + |
| 6 | +## 1. ScreenTapManager - 입력 처리 시스템 |
| 7 | + |
| 8 | +### 1.1 개요 |
| 9 | +`ScreenTapManager`는 플랫폼별 입력(터치/마우스)을 통합 관리하는 싱글톤 클래스입니다. |
| 10 | + |
| 11 | +### 1.2 주요 인터페이스 |
| 12 | + |
| 13 | +#### IInputProvider |
| 14 | +```csharp |
| 15 | +public interface IInputProvider |
| 16 | +{ |
| 17 | + bool TryGetPosition(out Vector3 position); |
| 18 | +} |
| 19 | +``` |
| 20 | +- 현재 입력 위치를 반환하는 인터페이스 |
| 21 | +- 터치/마우스 입력을 통합 처리 |
| 22 | + |
| 23 | +#### IInputUpProvider |
| 24 | +```csharp |
| 25 | +public interface IInputUpProvider |
| 26 | +{ |
| 27 | + bool TryGetPosition(out Vector3 position); |
| 28 | +} |
| 29 | +``` |
| 30 | +- 터치 종료 시점의 위치만 반환하는 인터페이스 |
| 31 | +- Raycast 이벤트 처리에 사용 |
| 32 | + |
| 33 | +### 1.3 구현 클래스 |
| 34 | + |
| 35 | +#### DefaultInputProvider |
| 36 | +- **플랫폼별 입력 처리**: iOS/Android는 터치, 데스크톱은 마우스 |
| 37 | +- **UI 무시 기능**: "IgnoreLookAt" 태그가 달린 UI 클릭 시 입력 무시 |
| 38 | +- **EventSystem 통합**: Unity UI 시스템과 연동하여 UI 오버레이 감지 |
| 39 | + |
| 40 | +#### DefaultInputUpProvider |
| 41 | +- **터치 종료 감지**: 터치/마우스 버튼 해제 시점만 감지 |
| 42 | +- **Raycast 이벤트**: 터치 종료 시점에만 이벤트 발생 |
| 43 | + |
| 44 | +### 1.4 주요 기능 |
| 45 | + |
| 46 | +#### LookAt 기능 |
| 47 | +```csharp |
| 48 | +public bool TryGetLookDirection(out Vector3 lookDir) |
| 49 | +``` |
| 50 | +- 스크린 좌표를 Live2D 모델이 사용할 방향 벡터로 변환 |
| 51 | +- 뷰포트 좌표계로 정규화하여 [-1,1] 범위로 변환 |
| 52 | + |
| 53 | +#### Raycast 기능 |
| 54 | +```csharp |
| 55 | +public bool TryGetTapUpPosition(out CubismRaycastHit[] hitResults) |
| 56 | +``` |
| 57 | +- 터치 종료 시점에만 Raycast 수행 |
| 58 | +- Live2D 모델의 특정 영역 터치 감지 |
| 59 | + |
| 60 | +## 2. SystemManager - 시스템 통합 관리 |
| 61 | + |
| 62 | +### 2.1 개요 |
| 63 | +Live2D 캐릭터 시스템의 전체적인 초기화와 관리를 담당하는 싱글톤 클래스입니다. |
| 64 | + |
| 65 | +### 2.2 주요 구성 요소 |
| 66 | +- **CubismLookTarget**: 시선 추적 타겟 |
| 67 | +- **Camera**: 메인 카메라 참조 |
| 68 | +- **ModelConfig**: 모델 설정 데이터 |
| 69 | +- **AudioSource**: 음성 입력 소스 |
| 70 | +- **Button**: 표정 변경 버튼 |
| 71 | + |
| 72 | +### 2.3 초기화 프로세스 |
| 73 | + |
| 74 | +#### Start() 메서드 |
| 75 | +1. `ScreenTapManager` 초기화 |
| 76 | +2. `AudioManager` 초기화 |
| 77 | +3. 모델 초기화 (`ModelInit`) |
| 78 | + |
| 79 | +#### ModelInit() 메서드 |
| 80 | +1. 기존 모델 제거 |
| 81 | +2. 새 모델 인스턴스 생성 |
| 82 | +3. LookAt 설정 |
| 83 | +4. LipSync 설정 |
| 84 | +5. Raycast 설정 |
| 85 | + |
| 86 | +### 2.4 설정 메서드들 |
| 87 | + |
| 88 | +#### SetLockAt() |
| 89 | +```csharp |
| 90 | +private void SetLockAt(ModelConfig modelConfig) |
| 91 | +{ |
| 92 | + var lookController = _currentModel.GetComponent<CubismLookController>(); |
| 93 | + lookController.Target = cubismLookTarget.gameObject; |
| 94 | + lookController.Damping = modelConfig.LockAtDamping; |
| 95 | + cubismLookTarget.Initialize(modelConfig); |
| 96 | +} |
| 97 | +``` |
| 98 | + |
| 99 | +#### SetLipSync() |
| 100 | +```csharp |
| 101 | +private void SetLipSync(ModelConfig modelConfig) |
| 102 | +{ |
| 103 | + var mouthController = _currentModel.GetComponent<CubismAudioMouthInput>(); |
| 104 | + mouthController.AudioInput = voiceSource; |
| 105 | + mouthController.Gain = modelConfig.Gain; |
| 106 | + mouthController.Smoothing = modelConfig.Smoothing; |
| 107 | +} |
| 108 | +``` |
| 109 | + |
| 110 | +#### SetRayCast() |
| 111 | +```csharp |
| 112 | +private void SetRayCast(ModelConfig modelConfig) |
| 113 | +{ |
| 114 | + var hitHandler = _currentModel.GetComponent<CubismHitHandler>(); |
| 115 | + hitHandler.Initialize(); |
| 116 | + expressionChangeBtn.onClick.AddListener(hitHandler.ExpressionChange_Btn); |
| 117 | +} |
| 118 | +``` |
| 119 | + |
| 120 | +## 3. CubismLookTarget - 시선 추적 타겟 |
| 121 | + |
| 122 | +### 3.1 개요 |
| 123 | +Live2D 모델의 시선 추적을 위한 타겟 클래스로, `ICubismLookTarget` 인터페이스를 구현합니다. |
| 124 | + |
| 125 | +### 3.2 주요 기능 |
| 126 | + |
| 127 | +#### Initialize() |
| 128 | +```csharp |
| 129 | +public void Initialize(ModelConfig modelConfig) |
| 130 | +{ |
| 131 | + _modelConfig = modelConfig; |
| 132 | +} |
| 133 | +``` |
| 134 | +- 모델 설정 데이터를 저장 |
| 135 | + |
| 136 | +#### GetPosition() |
| 137 | +```csharp |
| 138 | +public Vector3 GetPosition() |
| 139 | +{ |
| 140 | + if (!ScreenTapManager.Instance.TryGetLookDirection(out var lookDir)) |
| 141 | + return Vector3.zero; |
| 142 | + return lookDir * _modelConfig.LookSensitivity; |
| 143 | +} |
| 144 | +``` |
| 145 | +- `ScreenTapManager`에서 입력 방향을 받아서 민감도 적용 |
| 146 | +- 시선 추적 활성화 여부 확인 |
| 147 | + |
| 148 | +#### IsActive() |
| 149 | +```csharp |
| 150 | +public bool IsActive() |
| 151 | +{ |
| 152 | + return _modelConfig.IsLockAtActive; |
| 153 | +} |
| 154 | +``` |
| 155 | +- 모델 설정에 따른 시선 추적 활성화 상태 반환 |
| 156 | + |
| 157 | +## 4. CubismHitHandler - 터치 인터랙션 처리 |
| 158 | + |
| 159 | +### 4.1 개요 |
| 160 | +Live2D 모델의 특정 영역 터치를 감지하고 반응을 처리하는 클래스입니다. |
| 161 | + |
| 162 | +### 4.2 주요 구성 요소 |
| 163 | +- **CubismRaycaster**: 터치 감지를 위한 레이캐스터 |
| 164 | +- **CubismExpressionController**: 표정 변경을 위한 컨트롤러 |
| 165 | + |
| 166 | +### 4.3 초기화 |
| 167 | +```csharp |
| 168 | +public void Initialize() |
| 169 | +{ |
| 170 | + _raycaster = GetComponent<CubismRaycaster>(); |
| 171 | + _expressionController = GetComponent<CubismExpressionController>(); |
| 172 | + ScreenTapManager.Instance.SetRaycaster(_raycaster); |
| 173 | +} |
| 174 | +``` |
| 175 | + |
| 176 | +### 4.4 터치 처리 |
| 177 | + |
| 178 | +#### Update() 메서드 |
| 179 | +```csharp |
| 180 | +private void Update() |
| 181 | +{ |
| 182 | + if (ScreenTapManager.Instance.TryGetTapUpPosition(out var hits)) |
| 183 | + { |
| 184 | + foreach (var hit in hits) |
| 185 | + { |
| 186 | + if(hit.Drawable is null) continue; |
| 187 | + HandleHit(hit.Drawable.name); |
| 188 | + } |
| 189 | + } |
| 190 | +} |
| 191 | +``` |
| 192 | + |
| 193 | +#### HandleHit() 메서드 |
| 194 | +```csharp |
| 195 | +private void HandleHit(string drawableName) |
| 196 | +{ |
| 197 | + switch (drawableName) |
| 198 | + { |
| 199 | + case "HitAreaHead": |
| 200 | + Debug.Log("머리 터치 → 표정 변경 or 모션 재생"); |
| 201 | + ExpressionChange(); |
| 202 | + break; |
| 203 | + case "HitAreaBody": |
| 204 | + Debug.Log("몸통 터치 → 다른 반응"); |
| 205 | + break; |
| 206 | + } |
| 207 | +} |
| 208 | +``` |
| 209 | + |
| 210 | +### 4.5 표정 변경 기능 |
| 211 | + |
| 212 | +#### ExpressionChange() |
| 213 | +```csharp |
| 214 | +private void ExpressionChange() |
| 215 | +{ |
| 216 | + _expressionController.CurrentExpressionIndex = |
| 217 | + GetNextExpressionIndex(_expressionController.CurrentExpressionIndex, 0, |
| 218 | + _expressionController.ExpressionsList.CubismExpressionObjects.Length); |
| 219 | +} |
| 220 | +``` |
| 221 | + |
| 222 | +#### GetNextExpressionIndex() |
| 223 | +```csharp |
| 224 | +private int GetNextExpressionIndex(int current, int min, int max) |
| 225 | +{ |
| 226 | + return ((current - min + 1) % (max - min + 1)) + min; |
| 227 | +} |
| 228 | +``` |
| 229 | + |
| 230 | +## 5. ModelConfig - 모델 설정 데이터 |
| 231 | + |
| 232 | +### 5.1 개요 |
| 233 | +ScriptableObject 기반의 모델 설정 데이터 클래스로, Live2D 모델의 다양한 설정을 관리합니다. |
| 234 | + |
| 235 | +### 5.2 주요 설정 카테고리 |
| 236 | + |
| 237 | +#### 모델 정보 |
| 238 | +- **modelName**: 모델 식별용 이름 |
| 239 | +- **modelDescription**: 모델 설명 |
| 240 | +- **thumbnail**: 썸네일 이미지 |
| 241 | + |
| 242 | +#### 시선 설정 |
| 243 | +- **lookSensitivity**: 시선 추적 민감도 (0-30) |
| 244 | +- **lockAtDamping**: 시선 추적 반응 속도 (0-5) |
| 245 | +- **isLockAtActive**: 시선 추적 활성화 여부 |
| 246 | + |
| 247 | +#### 립싱크 설정 |
| 248 | +- **gain**: 음량 증폭 배율 (1-10) |
| 249 | +- **smoothing**: 입 움직임 부드러움 (0-1) |
| 250 | + |
| 251 | +#### 모델 프리팹 |
| 252 | +- **modelPrefab**: 실제 모델 프리팹 |
| 253 | + |
| 254 | +### 5.3 사용 예시 |
| 255 | +```csharp |
| 256 | +// natoriConfig.asset 예시 |
| 257 | +modelName: Natori |
| 258 | +modelDescription: "이지적인 집사" |
| 259 | +lookSensitivity: 5 |
| 260 | +lockAtDamping: 0.15 |
| 261 | +isLockAtActive: true |
| 262 | +gain: 10 |
| 263 | +smoothing: 1 |
| 264 | +``` |
| 265 | + |
| 266 | +## 6. 연관 클래스들 |
| 267 | + |
| 268 | +### 6.1 GameManager |
| 269 | +- 게임 전체의 초기화와 관리 |
| 270 | +- WebSocket, Session, HTTP API 클라이언트 관리 |
| 271 | +- 시스템 간 의존성 설정 |
| 272 | + |
| 273 | +### 6.2 AudioManager |
| 274 | +- 음성, BGM, SFX 소스 관리 |
| 275 | +- 현재는 기본 구조만 구현된 상태 |
| 276 | + |
| 277 | +### 6.3 Live2D 프레임워크 클래스들 |
| 278 | +- **CubismLookController**: 시선 추적 컨트롤러 |
| 279 | +- **CubismAudioMouthInput**: 립싱크 입력 처리 |
| 280 | +- **CubismRaycaster**: 터치 감지 레이캐스터 |
| 281 | +- **CubismExpressionController**: 표정 변경 컨트롤러 |
| 282 | + |
| 283 | +## 7. 시스템 아키텍처 |
| 284 | + |
| 285 | +### 7.1 데이터 흐름 |
| 286 | +``` |
| 287 | +사용자 입력 → ScreenTapManager → CubismLookTarget → CubismLookController → Live2D 모델 |
| 288 | +터치 종료 → ScreenTapManager → CubismHitHandler → CubismExpressionController → 표정 변경 |
| 289 | +``` |
| 290 | + |
| 291 | +### 7.2 의존성 구조 |
| 292 | +``` |
| 293 | +SystemManager |
| 294 | +├── ScreenTapManager (싱글톤) |
| 295 | +├── AudioManager (싱글톤) |
| 296 | +├── CubismLookTarget |
| 297 | +├── ModelConfig (ScriptableObject) |
| 298 | +└── CubismHitHandler |
| 299 | +``` |
| 300 | + |
| 301 | +### 7.3 초기화 순서 |
| 302 | +1. `SystemManager.Start()` 호출 |
| 303 | +2. `ScreenTapManager.Initialize()` - 카메라 설정 |
| 304 | +3. `AudioManager.Initialize()` - 오디오 시스템 초기화 |
| 305 | +4. `ModelInit()` - 모델 생성 및 설정 |
| 306 | +5. 각 컴포넌트별 초기화 메서드 호출 |
| 307 | + |
| 308 | +## 8. 확장성 및 개선 사항 |
| 309 | + |
| 310 | +### 8.1 현재 구조의 장점 |
| 311 | +- **모듈화**: 각 기능이 독립적인 클래스로 분리 |
| 312 | +- **설정 기반**: ScriptableObject를 통한 데이터 관리 |
| 313 | +- **플랫폼 호환성**: 터치/마우스 입력 통합 처리 |
| 314 | +- **확장성**: 인터페이스 기반 설계로 새로운 기능 추가 용이 |
| 315 | + |
| 316 | +### 8.2 개선 가능한 부분 |
| 317 | +- **에러 처리**: 예외 상황에 대한 처리 부족 |
| 318 | +- **성능 최적화**: Update() 메서드의 최적화 필요 |
| 319 | +- **설정 검증**: ModelConfig의 유효성 검사 추가 |
| 320 | +- **로깅 시스템**: 디버깅을 위한 로깅 시스템 구축 |
| 321 | + |
| 322 | +## 9. 결론 |
| 323 | + |
| 324 | +이 시스템은 Live2D 캐릭터와의 상호작용을 위한 잘 구조화된 아키텍처를 제공합니다. 입력 처리, 시선 추적, 터치 인터랙션, 그리고 설정 관리가 체계적으로 분리되어 있어 유지보수성과 확장성이 우수합니다. 특히 ScriptableObject를 활용한 설정 관리와 인터페이스 기반 설계는 코드의 재사용성과 테스트 용이성을 높여줍니다. |
| 325 | + |
| 326 | + |
| 327 | + |
| 328 | + |
| 329 | + |
0 commit comments