627 lines
77 KiB
Markdown
627 lines
77 KiB
Markdown
# MagnetismHeroes 개발 계획
|
|
|
|
2026-10-06 승인된 범위 변경: 첫 버전은 효과음·배경음악을 제외한다. 아래 음원 요청표·음악 반복/믹싱·효과음 인수는 향후 참고이며 T7/T8의 필수 완료 기준에서 제외한다. 한국어 숫자·안내 음성 44개, 시각 연출, 오프라인 재생·순차 발화·마지막 숫자·화면 전환/일시 정지 정리 검증은 유지한다. 기존 null 음원 연결은 범위 제외 상태로 인정하며 임시 음원을 새로 채택하지 않는다. T7은 보존된 실제 검증과 앱 blob 동일성·새 범위의 독립 검토로 마감하고, T8은 Final 네 단계와 전체 진행·독립 복원을 새로 검증한다.
|
|
|
|
## 실행 방향과 현재 상태
|
|
|
|
한국어·오프라인·안드로이드 가로 화면의 30개 스테이지 체험판을 만든다. 수학 규칙은 순수 C#으로 구현하고 Unity는 입력·공간·표현·저장 연결을 담당한다. 작은 퍼즐 하나의 입력부터 저장까지 완성한 후 합체·분리와 전체 콘텐츠를 확장한다. 첫 퍼즐부터 Android를 검증하며, 마지막에는 완성된 APK로 전체 검증을 반복한다.
|
|
|
|
현재 저장소에는 게임 코드·Unity 프로젝트 설정·자동 검사 명령이 없다. 아래 경로·클래스 역할·명령은 **개발하면서 만들 대상**이다. 이 문서 작성에서 테스트·APK 제작·가상 기기 실행을 완료한 것으로 해석하지 않는다. 기존 게임 규칙과 R07의 30개 스테이지 표는 유지한다.
|
|
|
|
## 1. 아키텍처와 책임 경계
|
|
|
|
책임을 아래처럼 나누되 각 책임마다 별도 범용 프레임워크를 만들지 않는다.
|
|
|
|
| 책임 | 소유하는 내용 | 하지 않는 일 |
|
|
|---|---|---|
|
|
| Core의 수학 규칙 | 구 ID, 묶음 소속, 합체·분리, 계수 기록, 목표 다중집합 판정, 공급 한도 | GameObject·Transform·UI·파일 접근 |
|
|
| Core의 진행 제어 | 스테이지 시작·복원, 유효한 조작 실행, 정답·완료 전이, 자유 놀이, 저장 요청 | 입력 장치 읽기, 얼굴·애니메이션 구현 |
|
|
| Unity 입력·공간 연결 | 터치 해석, Raycast, 끌기 미리보기, 카메라, 흡착 후보, 확정 조작 전달 | 접촉 프레임을 근거로 구 복제·삭제·정답 처리 |
|
|
| Unity 화면·소리 표현 | Presenter, 캐릭터·숫자·선택 강조, 메뉴, 안내, 효과음 | 독립적인 수량·완료 상태 보유 |
|
|
| Unity 데이터·저장 연결 | ScriptableObject 정의 변환, JSON 직렬화·파일 교체·복구 | 실행 중 고정 자산 수정, UI 객체 직렬화 |
|
|
| 시작 지점 | 규칙·진행·입력·표현·저장 구현의 직접 연결과 수명 관리 | 여러 곳에서 찾는 전역 서비스 등록 |
|
|
|
|
컴파일 참조는 `UnityRuntime → Core` 방향이다. Core는 UnityRuntime과 UnityEngine을 참조하지 않는다. 저장 구현은 Core에서 선언한 저장 경계를 구현한다. 시작 지점이 그 구현을 진행 제어에 전달한다. Editor 코드만 자산 제작·검사·빌드 API에 접근하며 런타임에서 Editor 코드를 참조하지 않는다.
|
|
|
|
초기 실행 어셈블리는 Core와 UnityRuntime 두 개로 충분하다. Core 안에서 수학 규칙과 진행 제어를 폴더로 구분한다. Editor와 EditMode·PlayMode 테스트는 별도 어셈블리로 분리한다. 파일마다 인터페이스나 어셈블리를 만들지 않는다.
|
|
|
|
### 상태가 바뀌는 한 경로
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
I["터치·버튼"] --> A["Unity 입력 해석"]
|
|
A --> C["진행 제어"]
|
|
C --> D["순수 C# 규칙 검증·상태 확정"]
|
|
D --> C
|
|
C --> P["Presenter·3D 표현"]
|
|
C --> S["저장 경계"]
|
|
S --> J["앱 전용 JSON 파일"]
|
|
```
|
|
|
|
예를 들어 3과 2를 붙이면 입력 연결이 두 묶음 ID를 전달하고, 규칙이 서로 다른 유효한 묶음인지 확인한 뒤 구 5개를 한 묶음으로 확정한다. 진행 제어는 목표 판정과 저장 요청을 처리하고 Presenter는 숫자 5와 얼굴 하나를 표시한다. 애니메이션 중간의 Transform이나 콜라이더 개수로 수량을 다시 판정하지 않는다.
|
|
|
|
끌기 중 위치·분리 선택·연출은 미리보기다. 저장과 정답 판정은 확정 상태를 기준으로 한다. 조작 취소나 핀치 전환은 R03의 마지막 확정 상태로 복구한다. 앱 일시 정지에서도 연출 중간값 대신 이 확정 상태를 저장한다. 저장 실패를 파일 저장 성공으로 보고하지 않으며 복구 경로는 R12를 따른다.
|
|
|
|
## 2. 적용할 디자인 패턴
|
|
|
|
| 방식 | 적용 지점과 목적 | 적용 범위 |
|
|
|---|---|---|
|
|
| 명시적 상태 머신 | 시작·선택·퍼즐·자유 놀이의 유효 전이와 일반/나누기 조작 구분 | 상태와 전이를 표·코드로 드러낸다. 상태마다 클래스를 만드는 것은 필수가 아니다. |
|
|
| Presenter | 상태를 숫자·얼굴·버튼·안내에 반영하고 UI 의도를 진행 제어로 전달 | UI에 수학 규칙을 넣지 않는다. 상태 변경을 구독한다면 해제도 같은 수명에서 처리한다. |
|
|
| 저장 인터페이스 | 진행 제어 검사에서는 메모리 저장 대역을, 실제 앱에서는 JSON 파일을 사용 | 파일 접근 경계 하나를 둔다. 범용 Repository 계층을 추가하지 않는다. |
|
|
| 직접 의존성 주입 | 시작 코드가 필요한 구현을 만들어 전달 | 외부 DI 컨테이너·전역 Singleton 서비스 탐색을 도입하지 않는다. |
|
|
| 데이터로 정의하는 스테이지 | 같은 규칙으로 30개 자산의 초기 구성·목표·배치를 실행 | 스테이지마다 별도 게임 로직을 작성하지 않는다. |
|
|
|
|
합체·분리·계수·공급·반납은 명시적인 조작 호출로 표현한다. 취소는 미리보기 취소이며 범용 실행 취소/재실행 시스템을 뜻하지 않는다. 호출 결과를 따라 상태와 화면을 갱신하므로 전역 이벤트 버스도 필요하지 않다. 구가 최대 10개인 이 프로젝트에서는 ECS나 대규모 객체 풀 도입보다 규칙과 화면의 일치를 우선한다.
|
|
|
|
## 3. Unity 제작 방식과 프로젝트 준비
|
|
|
|
프로젝트 초기화는 작업 번호 없이 실행 담당자가 수행한다.
|
|
|
|
- 저장소 루트에 설치된 Unity `6000.6.3f1`로 URP 프로젝트를 준비한다. Android Build Support와 Unity 제공 SDK·NDK·OpenJDK 설치는 확인되었으므로 설치를 반복하지 않는다. External Tools에서 실제 사용 경로를 확인한다.
|
|
- Input System·uGUI·TextMeshPro·Unity Test Framework의 에디터 호환 버전을 선택하고 `Packages/manifest.json`, 잠금 파일과 `ProjectSettings/`에 고정한다. 개발 도중 패키지나 에디터 버전을 임의로 올리지 않는다.
|
|
- `Assets/MagnetismHeroes/Core/`에 순수 데이터·수학 규칙·진행 제어·저장 경계를 둔다. `UnityRuntime/` 아래 `Interaction`, `Presentation`, `StageAssets`, `Persistence`, `Bootstrap`으로 Unity 책임을 구분한다.
|
|
- `Editor/`, `Tests/EditMode/`, `Tests/PlayMode/`, `Scenes/`를 별도로 둔다. 초기 어셈블리·공통 폴더 메타데이터·검증 진입점은 공통 준비에서 한 번 만든다. Core의 Unity 참조 금지는 어셈블리 설정으로 검증한다.
|
|
- 시작/선택 화면과 플레이 공간은 소수의 씬으로 관리한다. 친구·숫자·목표 패널·놀이터를 재사용 프리팹으로 만들며 30개 번호마다 씬을 복제하지 않는다.
|
|
- 코드는 외부 C# 편집기에서 작성하고 씬·프리팹·배치·색·조명·애니메이션 연결은 Unity 에디터에서 제작한다. Unity 자산을 수정할 때는 에디터가 정상적으로 읽는 생성·수정 경로를 사용하고 참조 누락을 확인한다.
|
|
- 실행 담당자가 단계마다 공통 씬·시작 연결·빌드 포함 목록을 갱신한다. 기능 작성자는 전용 코드·프리팹·자산을 제공하고 같은 공통 씬을 동시에 수정하지 않는다.
|
|
- Android Studio의 `Medium_Phone_API_37.0` AVD는 생성되어 있지만 실행 검증은 하지 않았다. 사용 가능한 ABI·그래픽 환경을 확인한다. Unity 빌드용 SDK와 Studio의 가상 기기용 SDK 경로를 혼동하지 않는다.
|
|
|
|
기본 그림은 단순 구와 임시 얼굴로 먼저 조작을 검증한다. 카툰 재질·세 테마 배경·표정·한국어 음성은 단계별로 확장하고 최종 파일로 교체한다. 아래 제작 절차와 음원·대본 요청을 첫 퍼즐부터 시작하여 전체 제작 단계까지 기다리지 않는다. 임시 자산으로 플레이가 된다는 사실과 R11·R14의 표현·소리 완성은 별개로 기록한다. 자산은 앱에 포함하며 런타임 다운로드를 요구하지 않는다.
|
|
|
|
### 합체 영웅의 제작 방향
|
|
|
|
**아이가 붙인 모양이 영웅의 몸이 되고, 연결되는 순간 대표 표정과 자력 망토가 완성된다.** R11의 외형과 변신 순서를 Presentation에서 구현한다. 자석 구, 대표 얼굴·얇은 마스크, 접촉부의 빛, 묶음 뒤의 리본형 자력 망토, 숫자 표시를 재사용 가능한 표현 요소로 준비한다. 묶음 소속과 배치에서 표시를 구성하며 숫자마다 고정된 몸체 프리팹으로 교체하지 않는다.
|
|
|
|
| 소개용 구성 | 자세·움직임의 예시 |
|
|
|---|---|
|
|
| 1인 친구 | 통통 움직이며 주변을 살피고 짧은 망토가 따라옴 |
|
|
| 2인 친구 | 붙은 두 구가 함께 기울며 균형을 잡음 |
|
|
| 3인 친구 | 삼각형은 안정적인 자세, 일렬 배치는 유연하게 움직이는 자세 |
|
|
| 5인 친구 | 둥근 묶음은 몸을 활짝 펴는 인상, 긴 묶음은 물결치는 움직임 |
|
|
|
|
위 형태는 소개·외형 검토용 예시다. 플레이 중 아이의 배치를 예시 형태로 바꾸지 않으며 6~10도 같은 표현 원칙으로 조합한다. 시안의 색과 마스크 윤곽은 고정하지 않고 개별 구·숫자·선택·계수 표시의 식별을 우선해 조정한다. 게임 안에서는 모든 구의 기본 크기를 같게 유지한다.
|
|
|
|
합체는 접근 미리보기 → 접촉 빛과 효과음 → 대표 얼굴·숫자·망토 통합 → 짧은 영웅 포즈로 표현한다. 분리는 선택 테두리·망토 흐름 → 끌어내기 확정 → 두 묶음 각각의 얼굴·숫자·망토 → 서로 바라보는 짧은 반응으로 표현한다. 선택만 한 상태, 0개·전체 선택, 취소에서 성공적인 분리 연출을 실행하지 않는다.
|
|
|
|
Presenter는 확정된 묶음 변화로 표현을 갱신한다. 흔들림·망토·접촉 빛은 수학 상태와 저장 좌표를 수정하지 않고 입력을 가로채지 않는다. 연속 조작·화면 전환·복원 시 지난 연출을 정리해 현재 묶음과 맞춘다. 기존 상태로 표현을 재구성하므로 외형만을 위한 저장 필드를 추가하지 않는다.
|
|
|
|
T2에서 기본 구·얼굴·숫자를 연결하고 T4에서 합체·분리 결과와 표현 전환 지점을 마련한다. T7에서 마스크·연결부·망토·표정·효과음을 완성하고 T8에서 최종 Android 화면과 반복 조작을 확인한다.
|
|
|
|
### 자산 제작·전달·검수
|
|
|
|
Unity에서 자석 구·표현 프리팹·재질·특수 효과를 만들고 Blender에서 입체 배경 소품을 제작한다. AI 이미지는 시안뿐 아니라 실제 얼굴·UI 그림·텍스처에도 사용한다. 효과음·음악의 선택은 사용자가 맡는다. 음성은 이미 설치한 conda `qwen3-tts` 환경의 Qwen3-TTS를 정비해 실행 담당자가 생성·검수한다. 필요한 자산을 요청하고 전달받거나 선택된 파일의 사용권·형식·품질을 확인해 게임에 연결한다. 사용자 선택을 대신해 무료 음원·직접 작곡·AI 음악으로 결정하지 않는다.
|
|
|
|
아래 수량은 **초기 제작 규모이며 조정 가능**하다. 같은 파일을 여러 용도에서 재사용할 수 있으나 필수 동작의 표현을 생략하지 않는다. 배경 테마 3개와 숫자 읽기 1~10은 기획서의 범위다.
|
|
|
|
| 자산 | 첫 퍼즐에서 준비 | 전체 버전 제작 목록 | 제작·연결 방식 |
|
|
|---|---|---|---|
|
|
| 자석 친구 | 구 1종, 대표 얼굴, 숫자 표시 | 공유 구 메시·재질, 얇은 마스크, 표정 6종(기본·관심·집중·웃음·격려·축하) | Unity 기본 구 또는 공유 메시, 얼굴 PNG/간단한 표면 메시, TMP 숫자; 10개 고정 몸체를 만들지 않음 |
|
|
| 배경 | 단순 입체 바닥·가림 소품으로 조작 검사 | 서로 다른 테마 3개, 공통 소품 4~6종과 테마별 주요 소품 3~4종 | Blender 모델 → FBX → URP 재질 → Unity 프리팹; 같은 테마 안에서도 배치를 바꿔 사용 |
|
|
| 화면 | 목표·나누기·도움·진행 버튼의 기본 표시 | 시작·스테이지 선택·플레이·자유 놀이에 필요한 아이콘과 패널 | AI 시안/이미지 정리 → 투명 PNG; uGUI 연결, 한글·숫자는 TMP |
|
|
| 글꼴 | 기본 한글·숫자 표시 | 실제 화면 문구·숫자·기호를 포함하는 글꼴과 TMP 폰트 자산 | 사용 조건이 확인된 한글 글꼴을 가져와 필요한 글리프를 구성; AI 그림으로 글자를 대체하지 않음 |
|
|
| 특수 효과 | 수집·계수 강조 | 흡착 후보, 연결 빛, 분리 선택/확정, 계수 표시, 도움 강조, 성공 효과와 자력 망토 | 공유 고리/리본 메시·재질, 작은 Particle System; 상태별 강조는 구별 |
|
|
| 효과음 | 아래 요청표의 첫 퍼즐 필수 음원 | 합체·분리·계수·격려·성공·화면·자유 놀이의 소리 | 사용자가 선택한 파일을 편집·음량 정리한 후 AudioClip으로 연결 |
|
|
| 한국어 음성 | ‘하나’와 수집/세기 안내 | 하나~열 10클립, 공통 안내, 합치기/나누기 시범, 상태별 도움 문구 | 대본 → conda Qwen3-TTS GPU·1.7B·Sohee → WAV → 발음·음량 검수 → AudioClip |
|
|
| 배경음악 | 임시 음악 또는 무음으로 기능 검사 | 놀이용 반복 음악 1곡과 메뉴용 편집본을 초기 요청 규모로 사용 | 사용자 선택 후 반복 구간·음량 편집; 3개 테마에 같은 곡을 사용할 수 있음 |
|
|
|
|
#### 캐릭터·배경·2D 제작 절차
|
|
|
|
1. R11의 외형을 기준으로 구, 얼굴·마스크, 연결 빛, 망토, 선택·계수 표시의 작은 스타일 시트를 만든다. 색·선 두께·광택·그림자 기준을 같은 시트에 기록한다. 기존 합체 영웅 그림은 참고 시안이며 그대로 3D 모델이 된 것으로 처리하지 않는다.
|
|
2. 구 하나와 2+3 합체, 5에서 떨어진 두 구를 선택한 분리를 먼저 Unity에서 표현한다. 기본·선택·계수 상태와 임의 입체 배열을 회전해 확인한 뒤 얼굴 그림·재질·소품을 확장한다.
|
|
3. AI 그림은 얼굴/마스크/아이콘/텍스처를 개별 요소로 생성한다. 공통 시안·스타일 지시를 재사용하고, 채택 결과의 여백·윤곽·투명 가장자리·색을 그림 편집 도구로 정리한다. 눈·입·마스크를 구 표면에 얹으며 숫자와 안내 문구를 이미지에 구워 넣지 않는다. 구 전체나 합체 몸체의 그림을 동적 3D 몸체로 대체하지 않는다.
|
|
4. Blender에서 둥근 모서리의 바닥·다리·받침·가림 소품을 공통 크기 기준으로 만든다. 불필요한 내부 면을 줄이고 피벗·스케일·회전·법선·UV를 정리한 뒤 선택한 모델을 FBX로 내보낸다. 모델 하나를 먼저 Unity에 넣어 방향·크기·재질·충돌 범위를 확인한 후 같은 방식으로 나머지를 제작한다.
|
|
5. Blender의 재질 노드가 Unity에 그대로 전달된다고 가정하지 않는다. Unity에서 공유 URP 재질과 제한된 색/텍스처 변형으로 장난감 질감을 구성한다. 단순 조명·그림자로 시작하고 후처리는 숫자와 개별 구가 읽히는 범위에서 조정한다.
|
|
6. 세 테마는 **정원 놀이터·구름 놀이터·별빛 공방**을 초기 미술 시안으로 제안한다. 이름·구체 소품·색은 조정할 수 있으며 테마 3개라는 범위는 유지한다. 정원은 잎/꽃/둥근 다리, 구름은 구름 받침/무지개 아치, 공방은 받침대/패널/별 모양 표지로 구별한다. 별·꽃 등 장식은 수량을 세는 자석과 외형·강조·입력에서 구별한다.
|
|
7. 배경은 카메라를 회전할 수 있는 입체 세트로 구성한다. 고정 카메라용 그림 한 장을 놀이터 전체로 사용하지 않는다. 테마는 스테이지 정의의 배치/장식 참조로 연결한다. 1~10/11~20/21~30에 각각 배정하는 것을 초기 배치값으로 두며, 배정 조정으로 R07의 순서·총량·목표를 바꾸지 않는다.
|
|
8. 모든 테마에서 자석은 장식 뒤·위에 놓을 수 있어도 회전하면 발견하고 집을 수 있어야 한다. 별도의 임무 장치·보행·새 성공 조건을 추가하지 않는다. 성공 후 자유 놀이와 이어하기에서도 해당 스테이지의 테마를 유지하며, 고정 정의와 `sourceStageId`에서 복원해 저장 필드를 늘리지 않는다.
|
|
|
|
Krita·Inkscape 같은 그림 편집기와 Audacity 같은 음원 편집기는 파일 정리용 도구 후보이며 필수 런타임 의존성이 아니다. 실행 시 사용 가능한 도구를 확인하고 필요한 무료 편집 도구만 준비한다. Blender·그림/음원 편집기 설치는 확인하지 않았다. Qwen3-TTS 패키지 설치와 클래스 import는 확인했지만 GPU 추론·음성 파일 생성은 아직 검증하지 않았다.
|
|
|
|
#### 특수 효과와 애니메이션
|
|
|
|
- 접촉 빛과 선택 강조는 공유 고리/윤곽 표현을 사용하되 형태·밝기·움직임을 다르게 한다. 이미 센 구의 표시는 지나가는 접촉 빛 뒤에도 유지한다.
|
|
- 자력 망토는 정지한 친구에게도 보이는 얇은 리본 메시로 만든다. 움직임에만 남는 TrailRenderer 하나로 망토 전체를 구현하지 않는다. 이동 꼬리는 보조로 사용할 수 있으며 망토는 안정 상태의 묶음마다 하나다.
|
|
- 성공은 짧은 작은 입자·표정·소리로 표현한다. 많은 입자나 큰 빛으로 구·목표를 덮지 않는다. 첫 버전에 전체 몸체 리깅·천 시뮬레이션·별도 대형 VFX 프레임워크를 요구하지 않는다.
|
|
- 떠오르기·기울기·망토 움직임은 표현용 하위 객체에서 실행한다. 기본 위치·구 ID·계수 기록은 바꾸지 않는다. 확정된 상태 변경과 후보/선택 미리보기를 구분해 재생하고 취소·후속 조작·복원 시 오래된 효과를 정리한다.
|
|
|
|
#### 효과음·음악 요청표와 사용자 선택
|
|
|
|
음원을 요청할 때 다음 표와 함께 용도 ID, 실행 화면/행동, 느낌, 권장 길이, 반복 여부, 필요한 단계, 파일 형식, 출처/사용권 정보를 전달한다. 아래 길이는 편집용 초기값이며 사용자 음원과 조작감에 맞춰 조정한다. 용도별 파일은 공유할 수 있고, 초기 UI는 임시 소리로 연결할 수 있으나 사용자 선택과 실제 재생 검수가 끝나야 최종 완성으로 처리한다.
|
|
|
|
| 용도 ID | 사용 시점·느낌 | 길이·반복 초기값 | 최초 필요 단계 |
|
|
|---|---|---|---|
|
|
| `sfx_pickup` | 친구를 집을 때, 가벼운 말랑함 | 0.1~0.3초, 1회 | T2 |
|
|
| `sfx_count` | 새 구를 셌을 때, 음성을 가리지 않는 짧은 톡 | 0.1~0.2초, 1회 | T2 |
|
|
| `sfx_ui` | 유효한 버튼 선택, 조용한 클릭 | 0.1~0.2초, 1회 | T2 |
|
|
| `sfx_success` | 퍼즐 성공, 부드러운 축하 | 1~2초, 1회 | T2 |
|
|
| `sfx_merge` | 합체 확정, 자석이 붙는 ‘착’ | 0.2~0.5초, 1회 | T4 |
|
|
| `sfx_split_select` | 분리 구 선택/해제, 작은 반응 | 0.1~0.2초, 1회 | T4 |
|
|
| `sfx_split` | 분리 확정, 연결이 풀리는 ‘톡’ | 0.2~0.5초, 1회 | T4 |
|
|
| `sfx_encourage` | 목표와 다른 구성/무효 조작, 부담 없는 반응 | 0.2~0.5초, 1회 | T4 |
|
|
| `sfx_spawn_return` | 자유 놀이 추가/반납 | 0.2~0.4초, 1회 | T5 |
|
|
| `sfx_hint` | 도움 강조, 주의를 부드럽게 끎 | 0.2~0.5초, 1회 | T6 |
|
|
| `music_play` | 퍼즐·자유 놀이, 가사와 긴장감 없는 반복 음악 | 60~120초, 반복 | T7 |
|
|
| `music_menu` | 시작/선택 화면, 같은 음악의 조용한 편집본 가능 | 30~60초, 반복 | T7 |
|
|
|
|
사용자가 파일을 제공하면 그 파일을 검수하고, 출처나 후보를 선택하면 허용된 파일을 확보하여 편집한다. 구매가 필요한 후보는 비용 조건을 먼저 제시하며 승인되지 않은 구매를 실행하지 않는다. 사용권을 확인하지 못한 후보나 사용자가 아직 선택하지 않은 임시 파일을 최종 자산으로 승격하지 않는다. 사용자 응답이 필요한 동안에는 해당 소리의 임시 연결과 다른 구현을 진행하되, 최종 음원 완료 항목은 미완료로 남긴다.
|
|
|
|
전달 규격의 초기값은 음성·효과음은 WAV/PCM 16bit·mono·44.1kHz, 음악은 WAV/PCM 16bit·stereo·44.1kHz다. 다른 형식의 허용된 파일을 받으면 원본을 보관하고 Unity 입력용 파일을 변환한다. TTS의 원래 출력 샘플레이트와 음악의 원래 채널 수는 보존 기록에 남기며, 샘플레이트·채널은 품질과 메모리를 확인해 조정할 수 있다. 숫자 클립의 이름은 대본표 ID와 일치시키고 잘리지 않은 한 발화를 담는다.
|
|
|
|
#### 로컬 TTS 대본과 출력 계약
|
|
|
|
로컬 Qwen3-TTS는 **제작 PC에서 음성 파일을 생성하는 도구**다. Unity 앱과 빌드에 TTS SDK·모델·서버를 추가하지 않는다. 생성된 WAV를 읽으면 되므로 Qwen의 Python API를 게임 코드에 결합하지 않는다. 환경·모델·파일·품질을 아래 절차에 따라 각각 확인하고 클라우드 TTS로 자동 전환하지 않는다.
|
|
|
|
| 음성 ID | 대본/생성 범위 | 연결 시점 |
|
|
|---|---|---|
|
|
| `count_01`~`count_10` | 하나, 둘, 셋, 넷, 다섯, 여섯, 일곱, 여덟, 아홉, 열 | 새 구를 센 순서의 개수; 숫자 기호를 TTS에 그대로 맡기지 않음 |
|
|
| `guide_collect` | ‘친구를 찾아 끌어와 볼까?’ | 수집 안내/도움 |
|
|
| `guide_count` | ‘모두 모았네! 하나씩 눌러 세어 보자.’ | 세기 안내 |
|
|
| `guide_merge` | ‘친구들을 가까이 붙여 볼까?’ | 합치기 시범/도움 |
|
|
| `guide_split` | ‘나누기를 누르고, 떼어 낼 친구를 골라 끌어내자.’ | 나누기 시범/도움 |
|
|
| `guide_find`, `guide_uncounted` | 찾을 자석/아직 세지 않은 구를 알려주는 짧은 문구 | R08의 현재 상태 도움 |
|
|
| `guide_split_N_K` | ‘네 개 친구에서 하나를 떼어 볼까?’처럼 실제 힌트에 쓰는 N·분리 개수 K별 문장 | 목표에 접근하는 분리 도움 |
|
|
|
|
대본은 초기 문안이며 같은 의미의 자연스러운 한국어로 다듬을 수 있다. N에 따라 달라지는 조사는 문장 단위로 생성·검수하고 숫자 클립을 기계적으로 이어 붙여 어색한 문장을 만들지 않는다. 분리 안내 ID의 N은 2~10, K는 1~N-1이며 실제 도움에 사용하는 쌍을 대본표에 기록한다. 위 예시 목록만으로 실제 힌트의 모든 분리 수를 하나로 고정하지 않는다. T6에서 실제 화면 안내·힌트 종류와 대본을 대조해 필요한 문장을 빠짐없이 요청한다.
|
|
|
|
실행 담당자가 음성 ID·화면 문구·발화 문구·사용 조건·필요 단계를 담은 대본표와 생성 프로필을 만들고 선택된 Qwen 환경에서 생성한다. 생성 도구명·버전·모델·목소리 식별자·설정과 사용 조건을 기록한다. WAV는 원본으로 보관하고 앞뒤 과도한 무음·잘림·잡음·발음 오류를 편집/재생성으로 수정한다. 모든 숫자와 실제 안내 문장을 듣고 확인하며 무음 파일·다른 숫자·누락을 통과시키지 않는다. 모델을 앱에 배포하지 않아도 결과물의 사용 가능 범위는 확인한다.
|
|
|
|
#### Qwen3-TTS 제작 환경과 생성 절차
|
|
|
|
제작 도구는 로컬 Qwen3-TTS이며 기존 conda 환경 `qwen3-tts`를 재사용한다. **GPU·1.7B CustomVoice·한국어 Sohee**로 확정한다. 고정 목소리를 재사용하면서 말투 지시를 적용하는 방향이다. VoiceDesign·음성 복제·온라인 API·대화형 서버를 제작의 기본 경로에 추가하지 않는다.
|
|
|
|
**2026-10-04 읽기 전용 확인 결과**는 아래와 같다. 패키지 설치 확인과 실제 음성 생성은 다르며 이 기획 보강에서는 환경 변경·모델 다운로드·추론·음성 파일 생성을 수행하지 않았다.
|
|
|
|
| 항목 | 확인 결과 | 개발 실행에서 확인할 사항 |
|
|
|---|---|---|
|
|
| conda 환경 | `qwen3-tts` 존재; 환경의 Python 직접 실행 가능 | conda 실행 경로 또는 해당 환경 Python을 찾아 사용; 시스템 Python과 혼용하지 않음 |
|
|
| Python·Qwen | Python 3.12.15, `qwen-tts` 0.1.1, `Qwen3TTSModel` import 성공 | 실제 제작에 사용한 버전 기록과 샘플 생성 |
|
|
| 주요 패키지 | torch 2.14.1, transformers 4.57.3, soundfile 0.14.0, accelerate 1.12.0 | GPU 정비 후 필요한 호환 버전과 실행 결과 고정 |
|
|
| 현재 PyTorch | `torch.version.cuda = null`, `torch.cuda.is_available() = false` | CUDA 지원 PyTorch 구성과 실제 GPU 연산 검증 |
|
|
| 하드웨어 | RTX 4080 SUPER, 약 16GB VRAM, 드라이버 591.86 | 모델 로딩·실제 추론의 메모리/시간 확인; 하드웨어 존재만으로 통과 처리하지 않음 |
|
|
| import 경고 | FlashAttention 미설치, SoX 실행 파일 미발견; 클래스 import는 성공 | 경고와 실패를 구분하고 선택한 생성 경로의 필요성을 샘플로 확인 |
|
|
| 모델·음성 | 가중치 확보·모델 로딩·GPU 추론·WAV 생성 미검증 | 각각 실행 증거를 남기며 설치 완료로 대신하지 않음 |
|
|
|
|
개발 실행에서는 기존 환경의 패키지 이름·버전과 GPU 상태를 먼저 기록한다. 공식 PyTorch의 Windows/Python/CUDA 설치 조합 중 Qwen과 호환되는 구성을 사용하여 필요한 PyTorch 변경만 수행한다. 환경 전체 삭제·재설치나 관련 없는 패키지 일괄 업그레이드는 하지 않는다. conda가 셸 PATH에 없으면 확인한 conda 실행 파일 또는 해당 환경 Python을 사용하며 전역 Python으로 대신 실행하지 않는다.
|
|
|
|
CUDA가 활성화되고 작은 텐서 연산이 성공한 뒤 모델을 로딩한다. FlashAttention 설치를 성공 조건으로 삼지 않는다. 현재 Windows 환경에서는 `attn_implementation="sdpa"`를 초기값으로 사용하고 같은 GPU·모델에서 호환성 문제를 확인한 경우 `eager`로 조정할 수 있다. `device_map="cuda:0"`, `dtype=torch.bfloat16`, 배치 크기 1을 초기값으로 두고 장치 지원·메모리·음질을 확인해 dtype/배치를 조정한다. SoX 경고만으로 선택한 12Hz CustomVoice 경로를 실패 처리하거나 무조건 추가 설치하지 않는다. 실제 생성이나 채택한 편집 경로가 필요로 할 때 확인해 준비한다.
|
|
|
|
| 생성 항목 | 값·규칙 |
|
|
|---|---|
|
|
| 모델 ID | `Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice` |
|
|
| 모델 revision | 첫 제작에서 공식 저장소의 커밋 해시를 기록하고 그 스냅샷을 고정; 이후 조용히 최신 버전으로 변경하지 않음 |
|
|
| 언어·목소리 | `language="Korean"`, `speaker="Sohee"`; 로드한 모델의 지원 목록과 대조 |
|
|
| 생성 함수 | `Qwen3TTSModel.from_pretrained()` → `generate_custom_voice()` |
|
|
| 초기 말투 지시 | ‘5~7세 아이에게 이야기하듯 따뜻하고 밝게, 천천히 또렷하게 읽어 주세요. 숫자는 정확하게 읽고 과장된 비명이나 웃음소리는 넣지 마세요.’ — 조정 가능 |
|
|
| 생성 방식 | 한 모델을 로드하여 선택한 대본들을 순서대로 생성; 처음에는 한 클립씩 검수 |
|
|
| 출력 | 함수가 반환한 파형과 실제 sample rate로 원본 WAV 저장; mono/PCM 16bit·44.1kHz의 Unity용 편집본은 별도로 준비 |
|
|
|
|
가중치와 필요한 tokenizer·processor 파일은 게임 저장소 밖의 로컬 모델 캐시에 둔다. 최초 확보는 개발 단계의 모델 다운로드이며 앱의 네트워크 기능이 아니다. 고정 revision의 필요한 파일을 완전히 확보한 뒤 로컬 스냅샷 경로로 모델을 로드하여 구성 요소의 버전이 섞이지 않도록 한다. 설치된 Qwen wrapper에서 모델과 processor에 revision 인자가 모두 전달된다고 가정하지 않는다. 캐시 경로는 실행 환경에서 찾고 기기별 절대 경로를 게임이나 공용 제작 프로필에 박아 넣지 않는다.
|
|
|
|
모델·목소리·언어·GPU 실행이 준비되지 않으면 오류 원인과 미검증 상태를 남긴다. 다른 제작 구성을 자동 선택하지 않는다. Unity 기능 개발은 기존 정책에 따라 임시 파일로 진행할 수 있지만 Qwen 제작·최종 음성 항목은 완료로 표시하지 않는다. CUDA 연산 확인만으로 실제 GPU 추론을 통과시키지 않는다.
|
|
|
|
**개발하면서 만들 파일과 명령**은 다음과 같다. 현재 파일이나 실행 결과가 존재한다는 뜻이 아니다.
|
|
|
|
| 제작 대상 | 역할 |
|
|
|---|---|
|
|
| `tools/audio/generate_voice.py` | 기존 환경에서 대본 선택 생성·일치 파일 재사용·파일 검사·생성 이력 기록; Unity 실행 코드와 분리 |
|
|
| `SourceAssets/Audio/Voice/voice-catalog.json` | `schemaVersion=1`, `clips` 배열. 각 항목은 고유 `id`, 비어 있지 않은 `text`(발화할 한국어 전체 문장), `usage`(화면/행동 설명), `stageIds`(1~30의 관련 번호), `required`(필수 여부)를 가짐 |
|
|
| `SourceAssets/Audio/Voice/qwen-profile.json` | 모델 ID/revision, 언어/목소리, 말투 지시, device/dtype/attention, seed와 실제 생성 설정; 환경별 캐시 절대 경로와 비밀 값은 포함하지 않음 |
|
|
| `SourceAssets/Audio/Voice/generated/<runId>/` | 생성 회차별 원본 WAV와 `manifest.json`; ID·대본·프로필·결과의 대응을 보존 |
|
|
| `SourceAssets/Audio/Voice/edited/` | 채택한 편집 후보·편집 내역; 생성 원본을 덮어쓰지 않음 |
|
|
| `Assets/MagnetismHeroes/UnityRuntime/Presentation/Audio/Voice/` | 청각/형식 검수가 끝나 게임에 연결할 ID별 WAV |
|
|
|
|
카탈로그에 `count_01`~`count_10`과 앞 대본표의 안내/실제 도움 문구를 기록한다. 같은 클립을 여러 스테이지에서 사용할 수 있다. 개별 회차에서는 `--ids`로 해당 단계에 필요한 ID만 생성하며, 전체 제작 완료 검사는 카탈로그 전체의 필수 항목을 대상으로 한다. 선택하지 않은 후속 단계의 음성이 첫 샘플 검사에서 없다는 사실과 전체 제작의 누락은 구분한다.
|
|
|
|
생성 프로필의 필드는 `schemaVersion=1`, `modelId`, `modelRevision`, `language`, `speaker`, `instruct`, `device`, `dtype`, `attention`, `seed`, `generationParameters`다. `seed`는 초기값 42로 두고 생성 설정과 함께 조정할 수 있다. `generationParameters`에는 실제 적용한 생성 인자와 모델의 기본 설정을 기록한다. 특정 seed가 음질을 보증하거나 장치/라이브러리가 달라도 동일한 WAV를 보장한다고 주장하지 않는다.
|
|
|
|
manifest는 `schemaVersion=1`, 고유 `runId`, 생성 시각, 실제 패키지·장치 정보, 고정 모델 revision과 카탈로그/프로필 해시, `clips` 결과를 가진다. 각 클립은 `id`, 대본 해시, 해당 생성 설정의 해시, `result`(`generated`·`reused`·`failed`), 원본 생성 회차/파일 참조를 기록한다. 성공 결과에는 WAV 해시·실제 sample rate·채널·샘플 수·길이, 실패에는 오류를 남긴다. 생성 성공 표시는 청각 검수 통과 표시가 아니다. 채택한 원본과 Unity 편집본·검수 결과는 자산 기록에서 연결한다.
|
|
|
|
파일 재사용은 ID만으로 판단하지 않는다. 같은 대본·모델 revision·목소리·말투·실제 생성 설정과 파일 해시가 일치하는 원본만 재사용하며 원래 생성 이력을 참조한다. 문구·말투·모델 설정이 바뀌면 바뀐 클립을 새 회차의 후보로 생성하고 기존 채택 파일을 조용히 덮어쓰지 않는다. 생성 실패·중단에서 빈 WAV를 정상 파일로 등록하지 않는다. 새 파일이 검수될 때까지 기존 채택본은 유지하되, 대본/프로필이 바뀌어 현재 조건과 맞지 않는 기존본을 최신 검수 통과로 처리하지 않는다.
|
|
|
|
다음은 구현할 진입점의 계약이다. 기본 샘플 → 부분 확장 → 전체 생성 → 파일 검사 순으로 사용하며 실제 실행 후에만 증거를 기록한다.
|
|
|
|
```powershell
|
|
conda run --no-capture-output -n qwen3-tts python tools/audio/generate_voice.py --catalog SourceAssets/Audio/Voice/voice-catalog.json --profile SourceAssets/Audio/Voice/qwen-profile.json --ids count_01,count_04,count_07,count_10,guide_collect
|
|
conda run --no-capture-output -n qwen3-tts python tools/audio/generate_voice.py --catalog SourceAssets/Audio/Voice/voice-catalog.json --profile SourceAssets/Audio/Voice/qwen-profile.json
|
|
$qwenVoiceManifest = '<생성 도구가 출력한 manifest.json 경로>'
|
|
conda run --no-capture-output -n qwen3-tts python tools/audio/generate_voice.py --catalog SourceAssets/Audio/Voice/voice-catalog.json --profile SourceAssets/Audio/Voice/qwen-profile.json --validate-only --manifest $qwenVoiceManifest
|
|
```
|
|
|
|
`--ids`를 생략하면 카탈로그 전체를 생성한다. `--validate-only`는 명시한 manifest와 현재 카탈로그/프로필에 대해 파일·이력 검사만 하고 모델을 로드하거나 다운로드하지 않는다. 형식 오류·선택한 필수 ID 누락·생성 실패·해시 불일치는 0이 아닌 종료 코드와 ID별 오류로 보고한다. 검사 범위가 부분 ID인지 전체 필수 목록인지 기록한다.
|
|
|
|
**검증 순서와 합격 기준**은 다음과 같다.
|
|
|
|
1. 환경·패키지/import → CUDA 및 실제 장치 연산 → 고정 모델 로딩 → 실제 GPU 생성의 결과를 각각 기록한다. 생성 시간·사용 장치·메모리·반환 sample rate와 로그를 남긴다. 설치 확인으로 이후 검사를 통과시키지 않는다.
|
|
2. ‘하나·넷·일곱·열’과 수집 안내를 첫 샘플로 생성하여 숫자 발음·짧은 말의 잘림·Sohee 목소리·친근한 말투를 듣고 확인한다. 문제가 있으면 같은 승인된 모델/목소리에서 대본·말투·생성 설정을 조정해 다시 검수한 뒤 전체 생성으로 확대한다.
|
|
3. 자동 파일 검사는 카탈로그 ID/본문/번호 유효성, 선택 범위의 필수 ID, WAV 읽기·양수 길이/sample rate·유효 채널·유한 파형, 파일/대본/프로필 해시와 생성 결과를 확인한다. 원본의 반환 sample rate를 그대로 기록하며 편집본만 전달 규격에 맞춘다. 무음·클리핑 후보는 음질 검수 대상으로 보고하고 잘못된 발음을 자동 통과로 판정하지 않는다.
|
|
4. 모든 숫자 10개와 실제 게임에서 사용하는 안내·도움 문장을 청각 검수한다. 다른 단어/숫자·발음 오류·문장 잘림·음색 불일치·과장된 소리가 남으면 재생성/편집한다. 이 검수 결과와 채택 파일 해시를 자산 기록에 남긴다.
|
|
5. 채택 원본을 보존한 채 앞뒤 무음·음량을 정리하고 Unity용 WAV를 만든다. 현재 카탈로그/프로필과 채택본의 대응, 파일 ID, mono/PCM 16bit·44.1kHz의 초기 전달 규격을 확인한다. 반환 sample rate를 표기만 바꾸거나 새로 샘플링했다고 원래 품질이 올라간 것으로 간주하지 않는다.
|
|
6. Unity에서 숫자 읽기·안내·순차 재생·마지막 계수·음악 혼합·전환 정리를 검사하고, 같은 최종 APK의 AVD 오프라인 재생으로 확인한다. 제작 PC에서 Qwen이 실행됐다는 사실과 앱에서 올바른 파일이 재생된다는 사실을 별도 증거로 남긴다.
|
|
|
|
공식 코드/선택 모델 revision의 라이선스와 모델 카드·목소리 출처를 확인해 기록한다. 모델이 Apache-2.0으로 표시되어 있다는 사실을 음성 결과물의 독점권이나 음질 보증으로 바꾸지 않는다. 제작 도구에 원본 음성 입력·복제를 요구하지 않으며 Qwen 패키지·모델 캐시는 APK에 넣지 않는다. 기능 개발의 전체 검증 진입점은 기존 `tools/verify.ps1` 계약을 유지하고, 음성 제작 도구 검사는 각 단계에서 파일 증거를 제공한다.
|
|
|
|
#### Unity 오디오 연결
|
|
|
|
- Mixer는 Master 아래 Voice·SFX·Music으로 나눈다. Presenter가 확정된 조작/상태에 대응하는 소리 ID를 전달하며 오디오 재생 완료가 수학 상태·성공 판정을 결정하지 않는다. 숫자 읽기·안내·UI 소리는 카메라 회전으로 작아지지 않는 2D 재생을 기본으로 한다.
|
|
- 빠른 계수 탭은 입력과 계수 표시를 즉시 확정하고 숫자 음성을 계수 순서대로 재생한다. 같은 구를 다시 누르면 새 계수 음성을 추가하지 않는다. 최대 10개 안에서 음성이 서로 겹치거나 중간 숫자가 누락되지 않게 한다.
|
|
- 성공 후 같은 보드에서 자유 놀이로 넘어갈 때 대기 중인 마지막 숫자 읽기는 끝까지 재생한다. 축하 소리와 안내가 이를 덮지 않도록 낮추거나 뒤로 배치한다. 성공 후 자유 놀이의 새 조작도 막지 않는다.
|
|
- 화면/스테이지 전환과 앱 일시 정지에는 이전 음성 큐·효과를 정리한다. 복원 시 지난 숫자·성공 안내를 다시 재생하지 않는다. 상태가 바뀐 뒤에는 이전 상태용 대기 안내를 취소하며 계수의 숫자 순서를 안내로 끊지 않는다.
|
|
- 음성 중에는 음악을 낮추고 효과음도 발음을 덮지 않게 섞는다. 오답에 큰 경고음이나 벌점 느낌을 넣지 않는다. 재생 우선순위·음량·짧은 반복 제한은 듣고 조정한다. 별도 설정 화면 추가는 이번 자산 계획에 포함하지 않는다.
|
|
- 원본은 WAV로 보관한다. 짧은 효과음·숫자 음성은 mono·Decompress On Load·Preload Audio Data를 초기값으로 사용하고 긴 음악은 Streaming을 초기값으로 둔다. 실제 길이·메모리·지연을 Profiler와 Android 재생으로 확인해 조정한다. 압축된 원본을 다시 무손실로 바꿨다고 품질이 복구된 것으로 간주하지 않는다.
|
|
|
|
#### 원본·출처·진행 기록
|
|
|
|
개발 단계에서 `SourceAssets/Models/`의 .blend, `SourceAssets/Images/`의 편집 원본, `SourceAssets/Audio/`의 원음·대본·편집 자료를 보관한다. AI 입력/채택 결과/정리 과정을 `SourceAssets/Generation/`에 기록한다. Unity가 가져오는 FBX·PNG·WAV 및 재질·프리팹은 `Assets/MagnetismHeroes/UnityRuntime/Presentation/` 아래 Models·Textures·Materials·UI·VFX·Audio·Prefabs에 둔다. 제작 원본은 빌드 포함 대상으로 참조하지 않는다. TTS 모델·가상 환경·도구 캐시는 게임 소스/앱에 넣지 않는다.
|
|
|
|
개발하면서 `docs/asset-register.md`에 실제 자산 목록과 출처를 만든다. 자산 ID는 고유하며 최소한 다음 열을 기록한다.
|
|
|
|
| 기록 | 내용 |
|
|
|---|---|
|
|
| 식별·연결 | 자산 ID, 유형, 원본/Unity 파일 경로, 사용 화면·스테이지·용도 ID |
|
|
| 출처·권리 | 제작자/제공자, 원본 URL 또는 자체 제작, 확보 날짜, 라이선스·조건 증거와 필요한 고지 |
|
|
| 생성·수정 | 도구/모델 버전, 대본/프롬프트·설정, 채택 파일, 편집 내역; 도구가 제공하는 재현 정보도 보관 |
|
|
| 선택·검수 | 사용자 선택이 필요한 음원의 선택 결과, 임시/최종 구분, import·화면·소리 검수 결과와 증거 경로 |
|
|
|
|
CC0 등 무료 자산도 실제 파일과 해당 출처의 조건을 기록한다. AI 결과에 일괄적으로 독점권이나 무조건적인 상업 이용 가능성을 부여하지 않는다. 필요한 사용 고지는 개발 단계의 `ThirdPartyNotices.txt` 등 배포 가능한 파일에 모은다. 임시 자산이 정상 재생되었다는 기록과 최종 파일의 권리·품질 검수 완료를 구분한다.
|
|
|
|
#### 단계별 자산 완성 기준
|
|
|
|
| 단계 | 자산 작업과 완료 판단 |
|
|
|---|---|
|
|
| T2·T3 | 첫 구·얼굴·숫자·기본 UI·입체 임시 배경과 ‘하나’ 음성 연결; Android에서 포함 파일·한글·오프라인 재생을 조기 확인. 임시 소품·음원은 최종 완료가 아님 |
|
|
| T4 | 대표 합체·분리의 접촉빛·선택·표정/망토 전환 시제품; 실조작에 연결해 구/표시 보존 확인, 필요한 효과음 요청 |
|
|
| T5·T6 | 자유 놀이·도움·시범용 음원/대본 요청; 3개 테마의 입체 세트와 30개 배치 연결, 모든 구의 발견·조작 가능성 확인 |
|
|
| T7 | 사용자 선택 음원과 Qwen3-TTS 생성 파일, 최종 얼굴·UI·모델·재질·망토·VFX를 통합; 임시 파일 교체와 전체 출처 기록·품질 검수 완료 |
|
|
| T8 | 최종 자산을 포함한 동일 APK로 세 테마·오프라인 소리·연속 조작·복원을 검사; 실제 기기 성능 판정은 후속으로 구분 |
|
|
|
|
자산 합격 기준은 다음과 같다. 픽셀 모양을 고정하는 자동 검사나 테스트 수 늘리기로 시각·청각 검수를 대신하지 않는다.
|
|
|
|
- **모델·재질:** FBX 방향/스케일/피벗이 맞고 분홍색 오류 재질·뒤집힌 면·필수 참조 누락이 없다. 3개 테마가 실제로 구별되며 모든 배치에서 회전해 자석을 발견·선택할 수 있다.
|
|
- **얼굴·UI·효과:** 투명 가장자리·한글 글리프·숫자 잘림을 화면 비율별로 확인한다. 1~10과 직선/평면/입체 배열의 구 경계·대표 얼굴/숫자/망토 개수, 선택·계수 가독성, 연속 조작/취소/복원 정리를 R11대로 확인한다.
|
|
- **오디오:** 요청 용도와 실제 파일/대본이 일치하고 모든 숫자·안내를 들어 발음·잘림·잡음·음량을 확인한다. 빠른 계수 입력의 순서·마지막 숫자·오래된 안내 취소를 검수한다. 반복 음악은 실제 게임에서 최소 3회 반복하며 경계의 끊김·클릭음을 확인한다.
|
|
- **원본·권리·빌드:** 최종 사용 파일에 출처/조건 기록이 있고 필요한 고지를 포함한다. 임시·미선택·누락 파일을 완료 처리하지 않는다. 앱에 TTS 모델/SDK/키/다운로드 경로가 없어도 오프라인 재생되며 실제 빌드 포함 파일을 검사한다.
|
|
- **모바일 비용:** 처음에는 공유 재질·텍스처와 적은 입자로 구성한다. 얼굴/UI 텍스처는 512~1024px을 초기값으로 두고 결과에 맞춰 조정한다. 구 10개·망토/연결 빛·음성·음악·가장 많은 소품의 상태에서 드로우콜·투명 오버드로·메모리·음성 로딩·프레임 비용을 기록한다. 이 조정값이나 AVD의 FPS를 실제 스마트폰 합격 기준으로 선언하지 않는다.
|
|
|
|
### 고정 정의와 플레이 상태
|
|
|
|
| 구분 | 제작·저장 방식 | 수명 |
|
|
|---|---|---|
|
|
| 고정 스테이지 | Inspector에서 편집하는 ScriptableObject; R07·R12 필드와 배치 | 제작 시 변경, 실행 시 읽기 전용 |
|
|
| 런타임 정의 | 고정 자산을 변환한 순수 C# 데이터 | 스테이지 실행에 사용 |
|
|
| 플레이 상태 | 구 ID·위치·묶음·수집·계수·카메라 | 조작을 확정할 때 변경 |
|
|
| 이어하기 | R12의 JSON 버전 1, 퍼즐별 슬롯과 최근 자유 놀이 하나 | 앱 재실행 후 복원 |
|
|
| 화면과 연출 | 상태에서 계산한 얼굴·숫자, 임시 선택·애니메이션 | 다시 생성 가능, 별도 저장하지 않음 |
|
|
|
|
Inspector 편집과 빌드 전 검사에서 총량·빈 묶음·잘못된 번호·누락된 배치 참조를 발견한다. 실제 정답은 Core 규칙으로 판정한다. 편집기 검사를 통과했다고 구를 실제로 발견·조작할 수 있다고 판정하지 않는다.
|
|
|
|
## 4. 기능별 기획에서 구현까지의 반복 절차
|
|
|
|
각 기능은 아래 항목을 계획의 해당 작업 또는 작업 변경 설명에 먼저 정리한다. 별도의 기획 시스템이나 대규모 문서 묶음을 만들지 않는다.
|
|
|
|
1. **학습·놀이 목적과 요구사항:** 어떤 아이의 행동을 가능하게 하는지와 R번호를 적는다.
|
|
2. **입력과 상태 변화:** 시작 상태, 아이의 조작, 확정 시점, 결과 상태, 화면·소리 반응을 적는다.
|
|
3. **불변 조건과 경계:** 수량·ID 보존, 무효 선택, 조작 충돌, 저장·재진입의 기대 결과를 적는다.
|
|
4. **합격 사례:** 준비 상태/행동/기대 결과를 작성하고 자동 검사와 수동 플레이 검사를 구분한다.
|
|
5. **최소 구현과 연결:** 규칙과 그 경계를 검사한 뒤 프리팹·UI를 연결한다. 한 기능의 정상 흐름이 플레이되도록 만든다.
|
|
6. **검증과 수정:** 해당 기능의 검사와 대표 플레이를 수행한다. 실패하면 원인을 수정하고 관련 검사를 반복한다. 단계가 끝나면 전체 회귀 검사를 수행한다.
|
|
|
|
수학 상태·저장·입력 충돌처럼 오류 비용이 큰 부분은 합격 사례를 자동 테스트로 먼저 구현한다. 색·장식·단순 문구마다 구현을 그대로 복제하는 테스트를 만들지 않는다. 버그 수정에는 재현 가능한 검사나 수동 재현 절차를 남긴다. 기능 이름만 있고 판정할 결과가 없으면 구현 준비가 끝난 것이 아니다.
|
|
|
|
### 대표 기능의 설계 카드
|
|
|
|
| 기능 / 근거 | 준비 상태와 행동 | 확정 결과 | 경계·검증 방법 |
|
|
|---|---|---|---|
|
|
| 모아 세기 / R05 | N개가 있는 놀이터에서 직접 끌어 모으고 각각 탭 | 전부 수집·한 묶음·전부 계수할 때만 성공 | 1번도 수집 필요; 미수집/중복 탭 거부. Core 검사 + 실제 화면 |
|
|
| 합체 / R02·R06 | 2와 3인 친구를 가까이 끌기 | 구 ID 5개를 보존한 친구 하나, 얼굴·숫자 5 | 이동 프레임마다 중복 합체하지 않음. 규칙 + 입력 연결 |
|
|
| 분리 / R04 | 5에서 나누기, 떨어진 구 2개 선택 후 끌기 | 선택 2와 나머지 3, 얼굴·숫자 각각 하나 | 0개·전체 선택은 불변; 선택만 해서는 분리 안 됨 |
|
|
| 입체 조작 / R03 | 친구/빈 공간/UI 위에서 터치를 시작 | 친구 이동/시점 회전/UI 조작을 구분 | 핀치·취소·영역 밖 놓기에서 구 소실 없음. PlayMode + Android |
|
|
| 성공과 자유 놀이 / R08·R09 | 목표 구성을 만들기 | 완료를 한 번 확정하고 같은 공간 자유 놀이 | 잘못된 구성은 계속 조작; 공급 11번째 거부, 0개에서 복구 |
|
|
| 이어하기 / R10·R12 | 두 퍼즐과 자유 놀이를 별도로 변경 후 재실행 | 세 상태와 ID·배치·계수·카메라 각각 복원 | 재플레이 완료 기록 유지, 손상·저장 중단 검사 |
|
|
| 도움 / R08 | 현재 수집·계수·구성 상태에서 도움 누르기 | 지금 가능한 대상/첫 행동 강조 | 자동 정답 실행 없음; 현재 상태에 맞는 안내 검사 |
|
|
|
|
단계별 기능 목록은 위 카드 형식을 사용하되 합격 사례는 기획서의 전체 경계를 포함한다. 예를 들어 합체 테스트 하나가 저장·분리·힌트까지 대신 검증하지 않는다.
|
|
|
|
## 5. 개발·테스트 환경의 역할
|
|
|
|
**주된 반복 작업은 Unity 에디터에서 수행한다. Android 검증은 첫 퍼즐, 중요한 연결 변경, 최종 완성 시점에 수행한다.**
|
|
|
|
| 환경 | 확인하는 내용 | 실행 시점 |
|
|
|---|---|---|
|
|
| EditMode | 순수 C# 규칙·상태 전이·스테이지 정의·저장 검증 | 규칙·데이터·저장 변경마다 관련 검사, 단계 종료 시 전체 |
|
|
| PlayMode | 입력과 규칙 연결, 프리팹·숫자·얼굴, 전환·복원, UI 입력 차단 | 기능 연결마다 관련 검사와 수동 플레이 |
|
|
| Game View / Device Simulator | 가로 화면, 스마트폰·태블릿 화면 비율, 안전 영역과 글자 | UI·카메라·배치 변경 시 |
|
|
| Android Studio AVD의 실제 APK | 빌드·설치·앱 실행·Android 파일 저장·재시작·오프라인 | 첫 퍼즐에서 조기 검사; 입력·저장·빌드 설정 변경 시 관련 재검사; 최종 전체 |
|
|
| 실제 Android 기기 | 실제 다중 터치·손맛·가독성·성능·발열·배터리 | 기기 준비 후의 후속 범위 |
|
|
|
|
Input System의 마우스 터치 시뮬레이션은 단일 포인터 개발을 돕는다. 핀치는 테스트 입력으로 두 접점을 주입하고 에뮬레이터의 지원 입력으로 연결도 검사한다. 마우스 한 개로 플레이했다는 이유로 실제 두 손가락 조작을 검증했다고 기록하지 않는다.
|
|
|
|
Unity Device Simulator는 화면·안전 영역 검사 도구다. Android Studio AVD는 APK를 설치하는 별도의 운영체제 환경이다. 둘을 같은 검증으로 처리하지 않는다. Device Simulator는 대상 그래픽 백엔드와 실제 기기 성능을 재현하지 않는다. [Unity Android 시뮬레이터 설명](https://docs.unity3d.com/6000.6/Documentation/Manual/android-device-simulator.html)
|
|
|
|
프로젝트를 열어 둔 에디터와 별도 배치 프로세스가 같은 프로젝트를 동시에 수정하지 않도록 검사 진입점에서 실행 방식을 정리한다. 정상 개발 반복은 열린 에디터의 Test Runner를 사용할 수 있고, 단계별 결과를 기록할 때는 같은 테스트 목록으로 검증 진입점을 사용한다.
|
|
|
|
## 6. 테스트 합격 기준과 증거
|
|
|
|
합격 기준은 **요구사항 → 실패할 수 있는 경계 → 검사 사례 → 실행 증거** 순서로 만든다. 테스트 개수나 코드 커버리지 수치만으로 제품 완료를 선언하지 않는다.
|
|
|
|
| 대상 | 필수 합격 기준 | 증거 |
|
|
|---|---|---|
|
|
| 규칙 | 1~10의 유효 합체·분리에서 구 ID 집합 보존; 구마다 소속 하나; 빈 묶음 없음 | EditMode 결과 |
|
|
| 분리 경계 | 크기 1~10의 모든 비어 있지 않은 진부분집합 선택 검사; 0개·전체·다른 묶음 선택 거부 | 매개변수화 테스트; 실제 분리 연결은 별도 |
|
|
| 정답·계수 | [2,2]와 [4] 구분; 중복 탭 불가; 수집·한 묶음·계수 조건 모두 필요 | Core·진행 검사 |
|
|
| 스테이지 | R07과 30개 정의 일치; 번호·총량 유효; 실제 규칙 호출로 모든 목표에 도달 가능 | 정의 비교 + 해답 경로 검사 |
|
|
| 입력·표현 | 같은 터치를 UI/이동/회전/계수에 중복 사용하지 않음; 취소·핀치 전환 복구; 표시 수량 일치 | PlayMode 결과 + 플레이 기록 |
|
|
| 합체 영웅 | 2+3→5와 5→2+3의 얼굴·숫자·망토 수 일치; 1~10 구 보존; 다른 모양의 5가 같은 판정; 선택·계수 표시 식별; 연속 조작·복원 후 잔상 정리 | PlayMode 상태 연결 검사 + 모바일 화면 비율에서 수동 외형 검사 |
|
|
| 저장 | 두 퍼즐+자유 놀이 독립 복원; 성공 전이 일관성; 재플레이 완료 기록 불변; 저장 중단·손상 복구 | 파일 검사 + Android 재실행 증거 |
|
|
| 자산 | 원본 정의 불변; Missing Script/참조 누락 없음; 한국어 글자·필수 음성 실제 포함·오프라인 재생 | 자산 검사 + 화면·소리 점검 |
|
|
| 자산 제작·인수 | 세 테마 실제 구별·모든 구 접근 가능; 최종 파일의 출처·사용 조건·검수 기록; 사용자 선택 음원·로컬 TTS 출력 연결; 순차 발화·마지막 숫자·음악 반복·전환 정리 | 자산 목록 + 에디터 검수 + Final APK 오프라인 재생 기록 |
|
|
| Android 조기 | 첫 퍼즐 설치·실행·미완료 위치/카메라/계수 복원·완료 후 자유 놀이 진입 | FirstSlice APK·기기·로그·화면 |
|
|
| Android 최종 | 대표 흐름과 저장·해금·오프라인을 완성 APK에서 재검사 | Final APK·로그·화면·체크 결과 |
|
|
|
|
전체 목표 도달 검사는 단순히 목표 배열을 정답 함수에 넣는 방식으로 대체하지 않는다. 초기 상태에서 실제 합체·분리 호출을 통해 도달하고, 수 세기는 수집·계수 호출을 모두 수행한다. 시각적인 발견 가능성과 조작 가능한 배치는 화면에서 별도 확인한다.
|
|
|
|
해당 단계의 필수 검사 실패 0개, 필수 검사 누락·미실행 0개를 합격 조건으로 삼는다. 전체 테스트 실행 수가 0이면 성공이 아니다. 정상 플레이에서 처리되지 않은 예외와 예상하지 못한 오류 로그가 없어야 한다. 손상 저장 같은 부정 사례의 의도된 실패는 테스트에서 기대 결과로 확인한다.
|
|
|
|
각 단계 기록은 요구사항/사례 ID, 실행 시각, 에디터·패키지 버전, 소스 커밋과 미커밋 변경 유무, 실행 명령, 실행·통과·실패·미실행 수, 로그 위치를 가진다. Android 기록에는 APK 해시, AVD/API/ABI/그래픽 설정, 설치·실행 여부, 동작별 결과와 화면 증거를 추가한다. 증거를 만든 후 소스나 자산이 달라지면 영향을 받는 검사와 최종 빌드를 다시 수행한다.
|
|
|
|
실제 기기가 없으므로 FPS·발열 합격을 이번 에뮬레이터 수치로 정의하지 않는다. 최대 10개 상태에서 Unity Profiler로 프레임·할당·렌더링·음성 비용을 관찰하고 명확한 불필요 비용을 줄인다. 실제 기기 성능 기준과 최종 판정은 후속 검증에서 정한다. 탭/끌기 임계값, 흡착 거리, 카메라 범위, 연출 시간은 조정 가능한 값으로 관리한다.
|
|
|
|
## 7. 검증 진입점의 계약
|
|
|
|
공통 준비에서 `tools/verify.ps1`을 만들고 아래처럼 프로젝트 루트에서 실행한다. 아래 명령은 현재 존재하는 명령이 아니다.
|
|
|
|
```powershell
|
|
pwsh -NoProfile -File tools/verify.ps1 -Phase EditMode -Milestone FirstSlice
|
|
pwsh -NoProfile -File tools/verify.ps1 -Phase PlayMode -Milestone FirstSlice
|
|
pwsh -NoProfile -File tools/verify.ps1 -Phase AndroidBuild -Milestone FirstSlice
|
|
pwsh -NoProfile -File tools/verify.ps1 -Phase AndroidSmoke -Milestone FirstSlice
|
|
pwsh -NoProfile -File tools/verify.ps1 -Phase EditMode -Milestone Final
|
|
pwsh -NoProfile -File tools/verify.ps1 -Phase PlayMode -Milestone Final
|
|
pwsh -NoProfile -File tools/verify.ps1 -Phase AndroidBuild -Milestone Final
|
|
pwsh -NoProfile -File tools/verify.ps1 -Phase AndroidSmoke -Milestone Final
|
|
```
|
|
|
|
`Phase`는 위 네 값, `Milestone`은 `FirstSlice`, `Composition`, `Persistence`, `Content`, `Final`이다. 생략한 Milestone은 Final이다. 초기 단계는 그때 구현한 기능의 사례만 대상으로 삼고, Final은 기획서 전체를 검사한다. 초기 결과를 최종 전체 결과로 재사용하지 않는다.
|
|
|
|
| 단계 | 남길 결과 |
|
|
|---|---|
|
|
| EditMode | `artifacts/verification/<Milestone>/editmode.xml`, 실행 로그, 검사 범위 |
|
|
| PlayMode | `artifacts/verification/<Milestone>/playmode.xml`, 실행 로그, 검사 범위 |
|
|
| AndroidBuild | `artifacts/android/<Milestone>/MagnetismHeroes.apk`, 빌드 로그·설정·해시 |
|
|
| AndroidSmoke | `artifacts/verification/<Milestone>/android-smoke.md`, 기기 설정·로그·화면 증거 |
|
|
|
|
마지막 APK는 `artifacts/android/MagnetismHeroes.apk`에도 제공하며 Final 검사 APK와 해시가 같아야 한다. 에디터·Android 도구는 설치 환경에서 찾고 특정 사용자 폴더를 소스에 고정하지 않는다. 프로세스 종료 코드뿐 아니라 검사 결과 파일·실행 수·실패·누락과 APK 존재도 확인한다.
|
|
|
|
AndroidSmoke는 APK 설치·앱 실행과 재현 사례의 증거를 모으는 진입점이다. 자동화할 수 없는 화면·소리 사례는 번호가 있는 수동 절차와 결과로 확인하며, 설치 성공만으로 이를 자동 통과시키지 않는다. 에뮬레이터 실패·미실행은 비정상 종료와 이유를 남긴다. ABI 불일치·가상화·그래픽 오류는 제품 규칙 실패와 구분하되 완료된 검사로 표시하지 않는다.
|
|
|
|
## 8. 단계별 구현 작업
|
|
|
|
### T1 — 순수 C# 규칙과 상태 계약
|
|
|
|
**목표:** Unity 없이 구·묶음·계수·정답·공급 규칙을 검증하고 이후 단계의 공통 데이터와 진행/저장 경계를 마련한다.
|
|
|
|
**근거:** R02, R04, R05, R06, R09, R12, R13.
|
|
|
|
**작업 대상:** `Assets/MagnetismHeroes/Core/`, `Tests/EditMode/Core/`.
|
|
|
|
**동작 계약:** 값은 구 개수에서 계산하고 구마다 묶음 하나를 보장한다. 합체·분리는 ID 집합을 보존한다. 무효 선택은 상태를 바꾸지 않는다. 목표 다중집합을 비교하고 수집·계수 ID는 이동·합체·분리로 초기화하지 않는다. 자유 놀이 공급·반납은 0~10 경계를 지키며 퍼즐 중에는 거부한다. R12의 정의·저장 데이터 필드와 제약을 보존한다.
|
|
|
|
**검증:** 모든 유효 분할, 다른 묶음 ID·중복 ID·빈 묶음·[2,2]/[4]·계수 경계·10개 한도를 검사한다. Core에 Unity 참조가 없고 EditMode가 통과해야 한다.
|
|
|
|
**공유 작성:** 공통 패키지·어셈블리·씬은 실행 담당자가 관리한다. 이 단계는 전용 Core 코드와 검사만 작성한다.
|
|
|
|
### T2 — 1번 수 세기의 첫 완성 흐름
|
|
|
|
**목표:** 1번을 시작해 직접 수집·계수하고 성공 후 같은 공간의 기본 자유 놀이로 들어가는 작동하는 흐름을 만든다. 성공 전 저장과 재시작 복원도 연결한다.
|
|
|
|
**근거:** R01, R02, R03, R05, R08, R09, R10, R11, R12, R13, R14.
|
|
|
|
**작업 대상:** Core의 진행 제어, `UnityRuntime/Interaction/`, `StageAssets/`의 1번 정의, `Presentation/`의 기본 화면·친구, `Persistence/`의 기본 저장, Qwen 생성 도구·초기 대본/프로필과 샘플 WAV, 대응 EditMode·PlayMode 검사.
|
|
|
|
**동작 계약:** 시작/선택에서 1번을 실행한다. 한 구도 직접 끌어 수집하고 한 번 눌러야 성공한다. 친구 이동·빈 공간 회전·핀치를 구분하고 UI 입력을 차단한다. 성공 전 구·카메라·계수 상태를 저장하며 성공 후 완료·퍼즐 제거·자유 놀이 생성은 같은 변경으로 처리한다. 숫자·얼굴과 같은 공간 전환을 최소 표현으로 연결한다.
|
|
|
|
**검증:** 1번 수집 생략 거부, 미완료 저장·복원, 중복 성공 거부, 카메라·조작 취소, 기본 자유 놀이 전환의 EditMode·PlayMode 및 실제 에디터 플레이를 통과한다.
|
|
|
|
**단계 범위:** 첫 저장부터 R12의 JSON 버전 1과 전체 필드 경계를 사용한다. 지원하는 플레이 경로는 먼저 1번이고 나머지는 T4~T6에서 확장한다. 임시 폰트·외관·소리와 제한된 콘텐츠를 최종 R11·30개 완성으로 표시하지 않는다.
|
|
|
|
구·기본 얼굴·숫자·UI·단순 입체 배경을 만들고, ‘하나’ 및 기본 안내 대본과 첫 효과음 요청을 준비한다. Qwen 환경의 GPU 지원을 정비하고 생성 도구·초기 카탈로그/프로필을 만들어 한국어 샘플과 필요한 첫 음성을 생성·검수한다. 중복 ID·잘못된 본문·누락/손상 WAV·대본/프로필 불일치의 파일 검사와 부분 재생성의 기존본 보존을 확인한다. 포함 파일의 한글·음성 재생을 연결하며, Qwen 출력이 준비되기 전의 임시 소리 검사와 최종 파일 검수를 구분한다.
|
|
|
|
**공유 작성:** 기능 코드는 전용 경로에 작성한다. 실행 담당자가 시작/플레이 씬·참조를 연결하고 FirstSlice 검사 범위를 기록한다.
|
|
|
|
### T3 — 첫 Android APK와 가상 기기 검사
|
|
|
|
**목표:** 첫 퍼즐을 실제 Android 앱으로 설치·실행하고 파일 저장·재시작을 확인해 플랫폼 문제를 일찍 발견한다.
|
|
|
|
**근거:** R01, R03, R05, R09, R10, R11, R12, R13, R14.
|
|
|
|
**작업 대상:** `Editor/`의 빌드 진입점, `tools/verify.ps1`의 Android 단계, FirstSlice 결과 경로, Android AVD.
|
|
|
|
**동작 계약:** AVD를 실행하고 adb 연결·ABI·그래픽 지원을 확인한다. APK의 대상 설정과 일치시켜 빌드·설치한다. 가로 화면·한국어 기본 표시·1번 수집/계수·같은 공간 자유 놀이를 확인한다. 성공 전 이동·카메라 변경을 저장하고 종료·재실행해 복원한다. 오프라인 실행을 확인한다.
|
|
|
|
**검증:** FirstSlice AndroidBuild·AndroidSmoke 실제 통과, APK·해시·로그·화면·절차별 결과를 남긴다. 빌드 성공만으로 실행 성공을 표시하지 않는다.
|
|
|
|
기본 모델·재질·글꼴과 준비된 음성/효과음이 APK에 포함되고 오프라인에서 재생되는지 확인한다. 이 단계에 사용한 임시/최종 자산과 아직 제공되지 않은 파일을 기록한다. 세 테마·최종 음악 전체의 검수는 T6~T8에서 수행한다.
|
|
|
|
1번은 한 번 세면 바로 성공하므로 성공 전 저장의 계수 목록은 비어 있다. FirstSlice에서는 이 빈 목록과 미완료 배치 복원을 검사한다. 일부 구만 센 미완료 상태의 복원은 T5의 저장 검사와 T6·T8의 N≥2 실제 스테이지 검사에서 확인한다.
|
|
|
|
**이유와 순서:** 첫 퍼즐의 Android 검사 후 확장하는 순서는 사용자와 정한 개발 방식이다. 환경 문제가 막으면 원인·미검증 항목을 보고하고 원인을 해결한다. 이 단계 실패를 숨겨 완료 처리하지 않는다.
|
|
|
|
**공유 작성:** 빌드 설정과 검사 진입점은 실행 담당자가 통합한다. 이 결과는 최종 검사를 대체하지 않는다.
|
|
|
|
### T4 — 합체·분리·혼합 퍼즐의 완성 흐름
|
|
|
|
**목표:** 6번·10번·14번을 대표로 합체·분리·혼합 조작을 기존 플레이 흐름에 추가한다.
|
|
|
|
**근거:** R02, R03, R04, R06, R07, R09, R11, R12, R13, R14.
|
|
|
|
**작업 대상:** Core 진행 제어 확장, Interaction과 기본 Presenter·프리팹, 대표 정의 자산, 대응 검사.
|
|
|
|
**동작 계약:** 가까운 친구에 붙이면 한 묶음이 된다. 나누기 → 구 선택 → 끌어내기로 선택/나머지를 각각 한 친구로 모은다. 떨어진 선택도 허용하며 분리 직후 의도하지 않은 재합체를 방지한다. 무효 선택은 상태 유지, 취소는 확정 상태 복구다. 14번은 행동 이력과 무관하게 최종 [2,2]로 판정한다. 회전해 공중 모든 방향을 편집할 수 있다.
|
|
|
|
**검증:** 6·10·14번 실제 규칙 해답과 화면 연결, 0개/전체/떨어진 선택, 핀치 전환·영역 밖 취소, 얼굴·숫자 일치를 검사한다. Composition EditMode·PlayMode와 변경된 입력의 Android 사례를 확인한다. 제작 중 대표 번호 직접 실행은 개발용 검사에만 사용하며 최종 순차 해금을 우회하지 않는다.
|
|
|
|
접촉 빛·선택·얼굴/망토 통합과 분리의 시제품을 실조작에 연결한다. 합체·분리 효과음을 요청하고 시범 대본을 Qwen 카탈로그에 추가해 생성·검수한다. 취소·연속 입력에서 상태보다 앞선 효과가 남지 않는지 확인한다. 최종 외형은 T7에서 마감한다.
|
|
|
|
**공유 작성:** 실행 담당자가 단계 씬을 갱신한다. 이전 1번 흐름과 FirstSlice 검사도 유지한다.
|
|
|
|
### T5 — 저장·진행·자유 놀이 전체 기능
|
|
|
|
**목표:** 첫 저장을 모든 미완료 슬롯과 최근 자유 놀이로 확장하고 10개 공급·반납과 진행의 수명을 완성한다.
|
|
|
|
**근거:** R08, R09, R10, R12, R13.
|
|
|
|
**작업 대상:** Core 진행/저장 경계, `UnityRuntime/Persistence/`, 관련 화면·검사.
|
|
|
|
**동작 계약:** 퍼즐별 하나씩 저장하고 자유 놀이는 전체 하나만 남긴다. 완료 기록은 재플레이로 취소되지 않는다. 공급·묶음 반납은 자유 놀이에서만 가능하며 0개 상태를 복구할 수 있다. 조작/카메라 확정·화면 이동·앱 일시 정지에서 저장한다. 성공 관련 상태는 일관되게 교체한다. 유효본 복구·손상 파일 보존·실패 기록을 제공한다.
|
|
|
|
**검증:** 두 미완료 퍼즐과 자유 놀이를 번갈아 저장·복원하고 ID·위치·소속·계수·카메라를 비교한다. 자동 저장 검사에는 N≥2에서 일부 구만 센 미완료 상태도 포함한다. 저장 중단·손상·자유 놀이 교체·재플레이·시범 기록을 검사한다. Persistence 단계의 Android 재시작·일시 정지 사례도 통과한다.
|
|
|
|
**공유 작성:** JSON 필드나 버전을 임의로 바꾸지 않는다. 같은 씬·저장 연결은 실행 담당자가 한 번 갱신한다.
|
|
|
|
### T6 — 30개 스테이지·도움·학습 안내
|
|
|
|
**목표:** R07 전체 정의와 실제 순차 해금·재플레이·도움·6/10번 시범을 완성한다.
|
|
|
|
**근거:** R05, R06, R07, R08, R09, R10, R11, R12, R13, R14.
|
|
|
|
**작업 대상:** StageAssets의 30개 자산·놀이터 배치, Core의 정의 검증·진행·힌트, 안내 화면, 검사.
|
|
|
|
**동작 계약:** 정의와 순서는 R07과 전부 일치한다. 수 세기는 정확히 N개를 제공하며 뒤·위에 있는 구도 찾고 잡을 수 있게 한다. 모든 퍼즐은 최종 조건으로 판정한다. 잠금/완료/이어하기를 표시한다. 시범은 첫 지정 시점에 한 번만 보이며 퍼즐을 대신 풀지 않는다. 도움은 현재 가능한 대상/첫 행동을 강조한다. 30번 후에는 존재하지 않는 다음 번호를 열지 않는다.
|
|
|
|
**검증:** 30개 자산의 번호·총량·목표·종류 검증, 실제 Core 호출로 전체 해답 경로, 새 저장에서 30번까지 해금, 다른 풀이·힌트 유효성·시범 재진입을 확인한다. 에디터에서 각 놀이터의 발견·조작 가능성을 플레이한다. Content 전체 EditMode·PlayMode와 변경된 진행 흐름의 Android 검사를 수행한다.
|
|
|
|
**공유 작성:** 번호마다 별도 씬·규칙을 만들지 않는다. 초기 배치와 장식은 자산·프리팹으로 관리한다.
|
|
|
|
Blender 소품과 공유 프리팹으로 세 테마의 입체 세트를 구성하여 고정 배치 참조에 연결한다. 테마별 발견·조작 가능성과 성공 후 동일 공간·복원된 테마를 확인한다. 실제 시범·현재 상태별 도움 문구를 Qwen 카탈로그에 빠짐없이 기록해 생성·검수하고, 최종 파일 교체에 필요한 전체 목록을 확정한다.
|
|
|
|
### T7 — 카툰 표현·한국어 음성·모바일 화면
|
|
|
|
**목표:** 검증된 기능을 아이가 읽고 만질 수 있는 최종 외관과 소리로 표현한다.
|
|
|
|
**근거:** R01, R02, R03, R04, R05, R06, R08, R09, R10, R11, R12, R13, R14.
|
|
|
|
**작업 대상:** Presentation의 캐릭터·UI·세 테마 놀이터·효과·한국어 음성·효과음·음악·글꼴, SourceAssets 제작 원본, 음원 요청/대본표·자산 출처와 사용 고지 기록, PlayMode 검사.
|
|
|
|
**동작 계약:** 묶음마다 얼굴·숫자 하나, 구별 선택/계수 강조, 부드러운 오답 반응, 성공 후 같은 공간을 제공한다. 가로 스마트폰·태블릿 비율과 안전 영역을 확인한다. 회전해도 숫자가 읽혀야 한다. 장식으로 구를 찾거나 잡을 수 없게 만들지 않는다. 필요한 한국어 숫자 읽기·안내·효과음을 허가된 실제 파일로 포함하고 오프라인 재생한다.
|
|
|
|
R11의 합체 영웅 외형과 변신 연출을 구현한다. 대표 얼굴과 얇은 마스크, 접촉부의 빛, 묶음마다 하나인 자력 망토로 합체·분리를 표현한다. 아이가 만든 기본 배치를 유지하며 각 구를 셀 수 있게 한다. 2+3의 합체와 5에서 떨어진 두 구를 고른 분리를 대표 연출로 제작하고, 1~10 및 임의 배열에도 적용한다. 연출의 취소·재진입·복원은 현재 확정 상태에 맞춰 처리한다.
|
|
|
|
**검증:** 얼굴·숫자·소속 일치, 시범·도움·오답·전환, 한글 누락·잘림·소리 누락, 입력 차단, 10개 한도·마지막 번호·복원 화면을 확인한다. 출처·사용 범위를 기록하며 임시 음성 또는 텍스트만으로 음성 완성을 선언하지 않는다. 전체 EditMode·PlayMode를 회귀 실행한다.
|
|
|
|
합체 전 두 얼굴·두 망토가 확정 후 각각 하나가 되고, 분리 후 두 묶음에 각각 하나씩 생기는지 검사한다. 선택만 한 상태·무효 분리·취소에서 묶음 구성과 얼굴·숫자·망토 개수가 바뀌지 않는지 확인한다. 연속 합체·분리와 연출 중 화면 이동·앱 복원 후 구 ID·계수·기본 배치가 유지되고 중복 얼굴·망토가 남지 않아야 한다. 직선·평면·입체 배열과 서로 다른 두 가지 5인 친구를 회전하며 구 경계·숫자·선택·계수의 가독성을 수동 확인한다. 이 검사를 장식의 픽셀 모양을 고정하는 자동 테스트로 대체하지 않는다.
|
|
|
|
**공유 작성:** 화면 작업에서 Core 규칙·저장 형식을 바꾸지 않는다. 실행 담당자가 최종 프리팹과 씬 연결을 갱신한다.
|
|
|
|
앞의 자산 제작 절차를 따라 AI 2D 그림·Blender FBX·URP 재질·망토/VFX와 Qwen3-TTS WAV의 최종 파일·출처 기록을 확인한다. 현재 카탈로그·고정 프로필의 전체 필수 음성에 대한 생성/재사용 이력과 파일 검사, 사용자 청취 승인 44개의 정확한 채택 해시를 유지한다. 필수 안내와 하나~열의 실제 재생, 빠른 탭 순차 발화와 성공 후 마지막 숫자, 화면 전환/일시 정지/복원 정리를 확인한다. 효과음·음악은 첫 버전에서 제외하여 반복·믹싱 청취 인수는 요구하지 않는다. 최종 사용 파일의 출처·조건·필요 고지가 누락되거나 필수 음성의 생성/청각 검수가 미완료이면 해당 항목을 통과로 표시하지 않는다.
|
|
|
|
### T8 — 최종 Android 전체 검증과 결과물
|
|
|
|
**목표:** 완성한 30개 체험판의 APK와 검증 증거를 제공한다.
|
|
|
|
**근거:** R01, R03, R07, R08, R09, R10, R11, R12, R13, R14.
|
|
|
|
**작업 대상:** 빌드/검증 진입점의 Final 범위, 최종 APK·자동 검사·Android 증거 경로.
|
|
|
|
**동작 계약:** 전체 EditMode·PlayMode를 실행하고 최종 자산을 포함한 APK를 빌드한다. AVD에서 설치·실행·수집·합체·분리·도움·시범·순차 해금·자유 놀이·오프라인 소리를 확인한다. 아래 대표 흐름과 두 미완료 퍼즐/자유 놀이 독립 복원을 재현한다. 첫 단계 증거와 최종 증거를 구분한다.
|
|
|
|
**검증:** Final 네 검사 단계, 실제 검사 수·실패/누락 여부, APK·해시·설정·로그·화면 기록을 확인한다. 결과를 통과/실패/미실행으로 구분하고 미실행이 있으면 전체 검증 완료를 선언하지 않는다. 실제 기기와 iOS·스토어 배포는 이번 범위가 아니다.
|
|
|
|
최종 파일·사용 고지가 포함된 APK에서 세 테마와 한국어 음성을 확인한다. 효과음·음악은 첫 버전에 포함하지 않는다. TTS 모델/서버/제작 도구 없이 오프라인 재생되며 빠른 계수·마지막 숫자·전환 정리가 유지되어야 한다. 에디터에서만 재생한 파일이나 다른 APK의 증거로 최종 앱의 음성 검사를 대체하지 않는다.
|
|
|
|
**공유 작성:** 최종 설정은 단독으로 갱신한다. 이때 기능을 고치면 관련 회귀 검사와 최종 APK/증거를 다시 만든다.
|
|
|
|
## 9. 단계별 장면 연결과 대표 플레이
|
|
|
|
장면 연결은 별도 작업 번호가 아닌 실행 담당자의 단계별 작업이다. T2 이후 각 단계의 프리팹·상태·입력·저장을 연결하고 검사한 뒤 다음 단계로 진행한다. 최종 T7까지 장면 연결을 미루지 않는다.
|
|
|
|
| 대표 흐름 | 실제 화면에서 확인할 결과 |
|
|
|---|---|
|
|
| 1번 | 직접 끌어 수집 후 한 번 눌러야 성공 |
|
|
| 6번 | 1과 1을 붙여 2; 최초 시범은 다음 진입에 자동 반복 안 됨 |
|
|
| 9번 | 2와 3을 합쳐 5; 구 다섯 알과 합체 후 얼굴·숫자·자력 망토 각각 하나 확인 |
|
|
| 10번 | 나누기·선택·끌기로 2를 1과 1로 분리; 선택만으로 성공 안 됨 |
|
|
| 13번 | 5에서 두 알을 선택해 2와 3으로 분리; 선택 중 강조와 확정 후 각 팀의 얼굴·숫자·망토 확인 |
|
|
| 14번 | 3과 1을 2와 2로; 다른 풀이 순서도 인정 |
|
|
| 20번 | 시점을 돌려 뒤쪽 구를 찾고 10개 수집·계수 전에는 완료 안 됨 |
|
|
| 30번 | 6과 4를 5와 5로 만들고 자유 놀이; 없는 다음 번호 표시 안 됨 |
|
|
| 저장 | 두 미완료 퍼즐과 최근 자유 놀이의 ID·배치·계수·카메라 독립 복원; N≥2에서 일부 구만 센 상태도 재실행 후 유지 |
|
|
| 자유 놀이 | 10개에서 추가 거부, 묶음 반납 후 추가, 빈 상태에서 다시 꺼내기 |
|
|
|
|
정상 순차 플레이 검사는 해금을 우회하지 않는다. 특정 경계의 자동 검사에서 상태를 준비하는 것과 실제 제품에 번호 우회 기능을 제공하는 것은 구분한다. 30개 자료·해답 검사는 위 대표 플레이만으로 대체하지 않는다.
|
|
|
|
## 10. 코드·자산 변경 규칙
|
|
|
|
- 네임스페이스는 `MagnetismHeroes` 아래 책임별로 나눈다. 타입·메서드·공개 속성은 PascalCase, 지역 변수는 camelCase, 비공개 필드는 _camelCase로 작성한다.
|
|
- Inspector 참조는 비공개 직렬화 필드로 드러내고 필수 참조 누락을 초기화·검사에서 발견한다. 고정 정의와 상태를 중복 소유하지 않는다.
|
|
- 데이터와 규칙의 변경 경로를 좁게 유지하고 정상적인 무효 조작은 거부 결과로 처리한다. 불가능한 상황을 위한 방어 계층을 여러 겹 만들지 않는다.
|
|
- `.meta`와 실제 소스·자산·프로젝트 설정은 함께 관리하고 생성 캐시·APK·검사 로그는 소스로 취급하지 않는다. 기존 Git 파일 변경과 커밋은 개발 실행 단계에서 담당한다.
|
|
- 기능 변경마다 영향을 받은 요구사항과 검증 결과를 남긴다. 관련 없는 리팩터링·프레임워크 추가·폴더 개편은 하지 않는다.
|
|
- 패키지 목록·어셈블리·씬·시작 연결·빌드 설정은 실행 담당자가 단독으로 갱신한다. 기능별 작업 대상과 겹치는 변경은 병합 전에 확인한다.
|
|
|
|
## 11. 요구사항 대응과 실행 그래프
|
|
|
|
| 요구사항 | 구현·검증 작업 |
|
|
|---|---|
|
|
| R01 | T2, T3, T7, T8 |
|
|
| R02 | T1, T2, T4, T7 |
|
|
| R03 | T2, T3, T4, T7, T8 |
|
|
| R04 | T1, T4, T7 |
|
|
| R05 | T1, T2, T3, T6, T7 |
|
|
| R06 | T1, T4, T6, T7 |
|
|
| R07 | T4, T6, T8 |
|
|
| R08 | T2, T5, T6, T7, T8 |
|
|
| R09 | T1, T2, T3, T4, T5, T6, T7, T8 |
|
|
| R10 | T2, T3, T5, T6, T7, T8 |
|
|
| R11 | T2, T3, T4, T6, T7, T8 |
|
|
| R12 | T1, T2, T3, T4, T5, T6, T7, T8 |
|
|
| R13 | T1, T2, T3, T4, T5, T6, T7, T8 |
|
|
| R14 | T2, T3, T4, T6, T7, T8 |
|
|
|
|
T2는 T1 규칙·데이터를 소비한다. T3는 T2의 실제 플레이·저장을 Android에서 검증한다. T4는 기존 플레이 경로를 확장하며 T3 뒤에 두는 것은 합의한 조기 플랫폼 검사 순서다. T5는 T4에서 확장한 묶음·조작 상태를 저장한다. T6는 T5의 진행·저장·자유 놀이 전체 수명을 사용한다. T7은 T6의 모든 목표·안내·진행 상태를 표현하고 T8은 최종 표현과 자산을 포함한 전체 앱을 검증한다.
|
|
|
|
현재는 같은 플레이 흐름을 단계마다 확장하므로 기능 단계를 순차 실행한다. 초기화와 단계별 공통 연결은 별도 그래프 작업으로 만들지 않는다. Qwen 음성 생성·부분 재생성은 T2·T4·T6·T7 내부의 제작 작업이며 후속 작업에는 검수된 파일과 기록을 전달한다. 작업 사이에 별도 일괄 재생성을 요구하는 단계는 없으므로 재생성 장벽은 두지 않는다. ScriptableObject의 일반 Inspector 편집·자산 검사도 코드 생성 장벽이 아니다.
|
|
|
|
```yaml
|
|
tasks:
|
|
- id: T1
|
|
depends: []
|
|
risk: RISKY
|
|
- id: T2
|
|
depends: [T1]
|
|
risk: RISKY
|
|
- id: T3
|
|
depends: [T2]
|
|
risk: RISKY
|
|
- id: T4
|
|
depends: [T3]
|
|
risk: RISKY
|
|
- id: T5
|
|
depends: [T4]
|
|
risk: RISKY
|
|
- id: T6
|
|
depends: [T5]
|
|
risk: RISKY
|
|
- id: T7
|
|
depends: [T6]
|
|
risk: RISKY
|
|
- id: T8
|
|
depends: [T7]
|
|
risk: RISKY
|
|
regen_barriers: []
|
|
```
|
|
|
|
## 참고한 공식 기술 문서
|
|
|
|
위 선택은 이 프로젝트의 규모와 합의한 Unity 제작 흐름에 맞춘 것이다. UI Toolkit도 현행 Unity에서 3D UI를 지원한다. uGUI 선택은 프리팹·MonoBehaviour 연결과 애니메이션 제작 흐름을 우선한 것이며 UI Toolkit의 기능 부재를 전제로 하지 않는다.
|
|
|
|
- [Unity URP 소개](https://docs.unity3d.com/6000.6/Documentation/Manual/urp/urp-introduction.html): 모바일을 포함한 렌더링 구성.
|
|
- [Unity UI 비교](https://docs.unity3d.com/6000.6/Documentation/Manual/UI-system-compare.html): uGUI·UI Toolkit 제작 방식과 지원 범위.
|
|
- [Input System 터치](https://docs.unity3d.com/Packages/com.unity.inputsystem@1.14/manual/Touch.html): EnhancedTouch와 포인터 기반 터치 시뮬레이션. 실제 패키지 버전은 초기화 시 에디터 호환 버전으로 고정한다.
|
|
- [Unity Test Framework 검사 구분](https://docs.unity3d.com/Packages/com.unity.test-framework@1.4/manual/edit-mode-vs-play-mode-tests.html): EditMode는 에디터에서, PlayMode는 에디터 또는 Player에서 실행 가능하다.
|
|
- [ScriptableObject](https://docs.unity3d.com/6000.6/Documentation/Manual/class-ScriptableObject.html), [어셈블리 구성](https://docs.unity3d.com/6000.6/Documentation/Manual/assembly-definition-files.html): 고정 자산 제작과 코드 참조 경계.
|
|
- [Unity 3D 파일 형식](https://docs.unity3d.com/6000.6/Documentation/Manual/3D-formats.html): 제작 원본을 별도로 두고 FBX 등 내보낸 파일을 가져오는 흐름.
|
|
- [AudioClip 가져오기](https://docs.unity3d.com/6000.6/Documentation/Manual/class-AudioClip.html), [Audio Mixer](https://docs.unity3d.com/6000.6/Documentation/Manual/AudioMixer.html): 클립별 메모리·재생 설정과 음성/효과음/음악 혼합.
|
|
- [TrailRenderer](https://docs.unity3d.com/6000.6/Documentation/Manual/class-TrailRenderer.html): 이동 흔적은 보조 표현으로 사용하고 정지 시 망토는 별도 리본 메시로 유지한다.
|
|
- [Qwen3-TTS 공식 코드·사용법](https://github.com/QwenLM/Qwen3-TTS), [선택한 1.7B CustomVoice 모델](https://huggingface.co/Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice): 한국어·Sohee·CustomVoice 생성과 모델 파일/라이선스 확인. 설치된 코드의 API와도 대조한다.
|
|
- [PyTorch 공식 설치 안내](https://pytorch.org/get-started/locally/): 개발 실행에서 기존 환경의 CPU 구성과 호환되는 Windows CUDA 구성을 확인한다. 특정 CUDA wheel 버전은 실제 호환성 검증 후 기록한다.
|