From 8f848acd58c19685be97e005e5f6e6e5e05a44c9 Mon Sep 17 00:00:00 2001 From: swrring Date: Mon, 18 May 2026 21:22:23 +0900 Subject: [PATCH] =?UTF-8?q?feat(BT13-Dev-Map=20Phase=201):=20=EB=A7=B5=20?= =?UTF-8?q?=EC=8B=9C=EC=8A=A4=ED=85=9C=20=EC=84=A4=EA=B3=84=20v1=201160=20?= =?UTF-8?q?=EB=9D=BC=EC=9D=B8=C2=B7PD=20=EA=B2=B0=EC=A0=95=2011=EA=B1=B4?= =?UTF-8?q?=20=EB=8C=80=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dev-team-lead Opus 직접 설계 — 프로젝트/EerieVillage/개발/spec/맵_시스템_설계_v1.md (1160 라인·18 섹션·신규). §2 사전 실측 13 sub-section — KinematicObject·PlayerController·PlatformerModel· Physics2D·EnemyController·GameOptimizer·Tile·Prefab·기획 SOT·BT12 영향·기존 MapGenerator 0건·Editor 폴더 직접 Read 검증. 점프 H_max=5.62m·D_max=6.42m 산출. 안전 거리 5.78m·안전 높이 5.06m (90% margin). §3 4계층 아키텍처 (시각 시뮬·절차 생성·데이터 SOT·런타임) + §4 절차 생성 알고리즘 (Intro/Mid/BossPre 청크·매번 완전 랜덤) + §5 Tile/Prefab 분리 + §6 발판 배치 룰 (점프 도달 거리 정합) + §7 GameOptimizer 위임/직접 분리 2옵션 + §8 거점+Start Point + §9 Enemy spawn (M001~M006) + §10 EditorWindow 1순위 + §11 ScriptableObject MapResourceCatalog + §12 기존 시스템 통합 + §13 Phase 2 작업 단위 + §14 기각안 6건 + §15 PD 결정 안건 11건 + §16 C50 Phase 2 토큰 옵션 (b 4분할·총 ~69K). §15 핵심: 15-1 기획 SOT §5 "수동 배치" OVERRIDE (level-designer 정정 의무) / 15-2 사선·이중 점프 / 15-3 chunk 옵션 / 15-4 Level/AutoForeground 분리 / 15-5 공중 발판 SpawnPoint / 15-6 Start Point 위치 / 15-7 Enemy 재-spawn / 15-8 Enemy spawn 방식 / 15-9 Boss 방 / 15-10 맵 길이 단위 / 15-11 옵션 노출. PM 정정 (pm-auditor Conditional Pass 정정 반영): - frontmatter "8건" → "11건" (Major 2 — dev-team-lead 자기 정합 누락 보완) C13·P19 PD 지시 로그 활성 테이블 BT13-Dev-Map 신규 등록. PD 직접 명세 (2026-05-18) + PD 결정 4건 (EditorWindow 1순위·Tile/Prefab 양쪽·완전 랜덤·옵션 미리 지정) 정합. Co-Authored-By: Claude Opus 4.7 (1M context) --- 공유/PD_지시_트래킹/개발팀_PD_지시_로그.md | 1 + .../EerieVillage/개발/spec/맵_시스템_설계_v1.md | 1160 +++++++++++++++++ 2 files changed, 1161 insertions(+) create mode 100644 프로젝트/EerieVillage/개발/spec/맵_시스템_설계_v1.md diff --git a/공유/PD_지시_트래킹/개발팀_PD_지시_로그.md b/공유/PD_지시_트래킹/개발팀_PD_지시_로그.md index 3cd07cb..0da7726 100644 --- a/공유/PD_지시_트래킹/개발팀_PD_지시_로그.md +++ b/공유/PD_지시_트래킹/개발팀_PD_지시_로그.md @@ -33,6 +33,7 @@ C3·C13 위반에 해당. **즉시 자진 보고 후 소급 등록**. | # | 일시 | 지시 요지 | 처리 상태 | 산출물 경로 | 중단 사유 | 사후 조치 | |---|------|----------|----------|-----------|----------|----------| +| BT13-Dev-Map | 2026-05-18 | **맵 시스템 설계 (C43 "개발팀" 호칭 직접 수령 + C49 1단계)** — PD 직접 발화 (2026-05-18): "이제 나는 우리 게임의 맵을 제작하고 싶어. 일반적인 플랫포머 맵 제작 방식 + 맵 길이 지정 시 랜덤 자동 생성 + 거점·Start Point 배치 + 거점 주변 몬스터 spawn (기존 이동 패턴 활용) + 시각 시뮬레이터 사전 확인 + 맵 리소스 등록 기능 + 발판 배치 점프 도달 거리 정합 + 바닥 충돌 자동 적용. 개발팀에서 충분히 논의 후 제안." **PD 결정 4건 (PM 사전 명세 답변)**: (1) Editor Window 1순위·어려우면 Scene 미리보기 fallback (2) Tile (배경) + Prefab (기믹) 양쪽 (3) 매번 완전 랜덤 (Seed X) (4) 맵 길이·비율 생성툴 옵션 미리 지정. **C50 사전 PD 옵션 보고 후 (a) 단일 설계 보고서 채택** (PM 자율·BT12-Dev Phase 1 선례). | **Phase 1 완료 2026-05-18 — PD 결정 11건 대기** | dev-team-lead Opus 직접 설계 — `프로젝트/EerieVillage/개발/spec/맵_시스템_설계_v1.md` (1160 라인·18 섹션 §1~§18). §1 요구 분석·§2 사전 실측 13 sub-section (KinematicObject body.Cast hitBuffer[16]·PlayerController maxSpeed 3·jumpTakeOffSpeed 7·PlatformerModel jumpModifier 1.5·Physics2D gravity -9.81·점프 H_max=5.62m·D_max=6.42m 산출·EnemyController patrolMin/Max 5/10·cliffCheck 1.0/2.0·groundLayerMask Layer 0+16·GameOptimizer SetupJumpThroughPlatforms·전 Tile m_ColliderType=1 사전 확정·기획 SOT §5 "수동 배치" OVERRIDE 발견·MapGenerator/Spawn 0건·EditorWindow 깨끗)·§3 4계층 아키텍처 (시각 시뮬·절차 생성·데이터 SOT·런타임)·§4 절차 생성 알고리즘 (Intro/Mid/BossPre 청크)·§5 Tile vs Prefab 분리·§6 발판 배치 룰 (안전 거리 5.78m·안전 높이 5.06m)·§7 바닥 자동 충돌 (GameOptimizer 위임 옵션 B 또는 직접 분리 옵션 A)·§8 거점+Start Point·§9 몬스터 spawn (M001~M006)·§10 EditorWindow 1순위 채택·§11 ScriptableObject MapResourceCatalog·§12 기존 시스템 통합·§13 Phase 2 작업 단위·§14 기각안 6건·§15 PD 결정 안건 11건·§16 C50 Phase 2 토큰 옵션 (b 4분할 권고·총 ~69K). | — | **PD 결정 안건 11건 수령 후 Phase 2 진입**. 핵심: 15-1 기획 SOT §5 "수동 배치" vs PD 신규 "랜덤 자동" 충돌 정정 (level-designer 후속) / 15-2 사선·이중 점프 도입 여부 / 15-3 chunk 옵션 노출 범위 / 15-4 Level/AutoForeground 분리 전략 (옵션 A 권고) / 15-5 공중 발판 SpawnPoint 허용 / 15-6 Start Point 좌측 고정 / 15-7 Enemy 재-spawn timer·count / 15-8 Enemy spawn 방식 (Enemy_M00N 직접 권고) / 15-9 Boss 방 포함 / 15-10 맵 길이 단위 (Tile 권고) / 15-11 옵션 노출 영역. Phase 2 = 옵션 (b) 4분할 (2-A 데이터 SOT ~12K + 2-B 절차 생성기 ~25K + 2-C EditorWindow+Applier ~22K + 2-D 정합 검증 ~10K · 총 ~69K). | | BT12-Dev-Clone | 2026-05-15 22:00 | **A10 분신 스킬 구현 (C43 호칭 + C49 시범)** — PD 직접 발화 (2026-05-15): "이번에는 분신 스킬을 구현해줘. 이 스킬을 사용하면 플레이어의 x좌표 1 뒤쪽에 반투명한 형태의 플레이어의 분신이 생성되어서 플레이와 동일한 스킬을 사용해야 해. (단, 분신의 공격은 플레이어의 공격력의 50% 반감되어야하고, 플레이어보다 0.5초 뒤 사용해야 해. 공격 시작 딜레이)". A10 = BT12-Dev 미구현 8종 중 1. BT12-Dev 보류 와중 PD 명세 확정 부분 구현. C49 시범 (개발팀장 Opus 설계 → 클라이언트팀 Sonnet 구현 → 개발팀장 검증). **PM 1차 합리적 기본값**: facing 반대 1유닛·alpha 0.5·lifetime 영구 1기 (새 발동 시 기존 대체)·무적 유지 (v0.4 CSV "분신은 무적이나 공격력 비율 감소" 정합)·collision 무충돌·Lv 업 1차 미반영 (후속 안건) **[1단계 완료 2026-05-15 16:56]** 개발팀장 Opus 직접 설계 — `프로젝트/EerieVillage/개발/spec/스킬_시스템_설계_v1.md §A10` 신설 (16 sub-section · 약 320 라인). 구조 결정 = (나) CloneInstance MonoBehaviour + 0.5초 지연 큐 + IsCloneFireActive 분기 (옵션 (가)·(다) 기각근거 명시). 신규 파일 2 + 수정 9 + asset 1 + 테스트 1 = 13 영역 작업 단위 분해. 기각안 5건 (별도 Inventory mirror·Effector 2회 발동·transform swap·8초 lifetime·독립 facing). EditMode 7건 신설 안. PD 결정 안건 3종 (BaseCooldown 30·facing 변경 시 위치·무적 spec). 스킬 이펙트 확정 SOT §3 A10 추가 (BaseCooldown 30·BaseDamage 0·Lifetime 영구·코드 하드코딩 영역 명시) + §4 변경 이력 갱신. | **진행중** | **1단계 완료** — 설계 문서 §A10·이펙트 SOT §3 A10·변경 이력 갱신 완결. **2단계 진행 영역** — 클라이언트팀 Sonnet Task 위임 영역 (신규 4 파일·수정 9 파일·asset 1·테스트 1·약 60~80K 추정). C50 영역 본 Task 누적 약 25K + 2단계 위임 약 60K + 3단계 검증 약 15K = 약 100K. C50 사전 PD 안내 영역 외 자체 판단 — PD 매니페스트 등록 시 인지 영역. | — | 2단계 결과 수령 후 3단계 개발팀장 검증 (C49 표준 프로세스 시범 영역) + PM 보고. **모호 영역 PD 결정 안건** (3단계 검증 보고 명시): (1) BaseCooldown 30 PM 추정 — balance-designer 후속 확정 (2) facing 변경 시 분신 위치 (spawn 시점 고정 vs Player 추종 동조) (3) 분신 무적 = 시각 GameObject 자체 (collider 미부착) — 적이 분신 위 올라타거나 적 투사체 통과 영역 Play 검증 (4) Lv 업 (분신 수 증가 등) 1차 미반영 영역 후속. **[BT12-Dev-Clone 완전 완료 2026-05-18]** α·β·γ·δ 4단계 전수 완료. **α**: CloneInstance.cs (218 라인)·CloneEffector.cs (24 라인) 신규. **β**: PlayerSkillInventory (필드 5종+이벤트)·ActiveSkillRuntime (Fire OnPlayerSkillFired·CalculateEffectiveDamage 50% multiplier)·SkillFireEvent (Minion CardId 분기·Cleanup reset)·SkillRuntimeFactory (A10 추가) 수정 4. **γ**: PlayerSkillInventory.GetSpawnAnchor·GetSpawnFacing helper 2 신설 + 6 Effector (Projectile·Laser·MeleeArea·LightningStrike·PoisonSwamp·SpiritFire) anchor·facing 분기 일관 적용. **δ**: A10_bunsin.asset (CardId A10·BaseCooldown 25·MinionLifetime 12·Category Minion) + CloneSkillTests.cs (EditMode 7건·PD 상수·multiplier·helper·Singleton·재귀 skip 검증) 신규. EerieVillage local commit `171506e` (18 파일 변경·PD Editor GitAutoSync 자동 push 대기·burning.i234.me origin 인증). 설계 v1 §A10 잔존 5 위치 (1423·1427·1431·1524·1572) PD 결정 정합 정리 완료. **[PD 결정 4건 2026-05-15 본 응답]** (1) BaseCooldown **25초** (PM 1차 30→PD 25) (2) MinionLifetime **12초** (PM 1차 영구 1기→PD 12초 자동 소멸·Singleton 유지) (3) facing 고정 확정 (4) 무적 Collider 미부착 확정 (5) Lv 업 시 분신 수 X·추후 지속시간↑+플레이어 참조 데미지 비율(%)↑ (balance-designer 후속 수치). SOT 설계 v1 §A10-1·이펙트 SOT v1 §3 A10·§4 변경 이력 PD 결정 반영 완료. **2단계 진행**: PM 권고 (b) 4분할 채택 — α CloneInstance·CloneEffector 신규 → β Inventory·Runtime·Event·Factory 수정 → γ 6 Effector → δ asset+EditMode. **[BT12-Dev-Clone 완전 완료 2026-05-18 — PD 확정 "좋아 이제 제대로 동작하는거 같아"]** EerieVillage commit 15건 누적 (`171506e` 초기 18 파일 → `412dedb` 최종). 본 PM 자성 #1~#7 (C39-10 위반 누적·feedback_new_code_existing_system_dependency_unmeasured) → PD 직접 지시 채택 "MCP 검증 강제" → 이후 모든 fix `refresh_unity`+`read_console`+`run_tests` 사전 검증. EditMode CloneSkillTests 7건 green (0.7초·T01~T07). 세션 종결 인수인계서 `공유/조직공지/2026-05-18_BT12-Dev-Clone_세션종결인수인계.md` + 대화로그 `공유/대화로그/EerieVillage/2026-05-18.md`. **PM 후속**: 본 commit 후 활성→완료 아카이브 이동·balance-designer 이관 (Lv 업 지속시간+데미지 비율(%) Lv별 수치) | | BT12-Dev-Vis | 2026-05-09 | **PlayerSkillInventory 등록 시각화 지시** — PD 직접 발화: "PlayerSkillInventory 등록이 되었는지 어떻게 판단해야하지? 시각적인 변화가 없으니 확인이 불가능해. 유니티 기본 제공 리소스를 활용해도 좋으니 보이게 해줘." **[2026-05-13 후속 세션 신규 3건]** (1) 투사체 사거리 파란 박스 시각화 — `HitboxDebug.SpawnRange` 신규 (`Projectile.Initialize` 끝 호출·3초 유지·`HideFlags.DontSave`). (2) 사정거리·속도 Inspector 직접 조절 — `ActiveSkillData.MaxRange`·`ProjectileSpeed` 신규 필드 (`RangeTier`·`camWidth`·`mults` 계산 폐기·`PiercingProjectile._speed = 2.5f` override 폐기). (3) A04 ExtraHitFxPrefab + FX_Thunder Smoke — `ActiveSkillData.ExtraHitFxPrefab` 신규·`LightningStrikeSpawner.DelayedExtraHitFx` Coroutine (0.6초 후 spawn·y -0.5·비주얼 전용·판정 무관). EerieVillage `ab40b27` push 정합. **[2026-05-13 사고 정정]** 본 PM `git reset --hard origin/main` 영역 PD Inspector 작업 .asset 6 폐기 사고 발생. PD 보고 "스킬 관련 스크립터블 오브젝트가 full 이후 롤백되어버렸어" 수령. `git reflog` 영역 `e2bc95f` 보존 정합·.asset 6 복구·EerieVillage `5b2a032` push 정합. A04 ExtraHitFxPrefab (FX_Thunder Smoke) 영역 PD 후속 Inspector drag&drop 필요. 본 PM 자성 #4 (헌법급) 등재. **[2026-05-13 신규 2건]** (1) 디버그 박스·사거리 박스 시각화 off (재활용 toggle) — `HitboxDebug.ShowDebugVisuals` 플래그 신규·4 위치 `SpriteRenderer.enabled` 정합. (2) 레벨업 카드 풀 5종 한정 — `SkillRuntimeFactory.AvailableCardIds` 화이트리스트 (A02·A13·A04·A05·A_Laser)·미완성 placeholder 5종 (A01·A03·A08·A14·A15) 제외. EerieVillage `d26bd83` push 정합. **잔여**: A04·A05·A_Laser 영역 SkillFireEvent default return 영역 실전 발사 미연결 (카드 풀 한정 영역과 별개·PD 후속 결정 대기). **[2026-05-13 정정·진단]** (1) A05·A_Laser 박스 시각 off 누락 정정 — MeleeAreaSpawner·LaserSpawner 영역 직접 SpriteRenderer 부착 코드 (HitboxDebug 미경유) 영역 `sr.enabled = HitboxDebug.ShowDebugVisuals` 추가. 본 PM 자성 #5 (변경 영향 사전 grep 누락). (2) Player 피격 X 진단 Debug.Log 추가 (회수 의무) — EnemyController.Update L387-396 영역 `[EnemyHit][Intersect]`·`[EnemyHit][Decrement]` 2종. PD Console 측정 결과 영역 근본 fix·Debug.Log revert. EerieVillage `e8779df` push 정합. **[2026-05-13 신규]** 게임 시작 시 기본 파이어볼 A02 자동 습득 — `PlayerSkillInventory.StartingCardIds` (string[]) Inspector 필드·기본 `{ "A02" }`·`Start()` 영역 일괄 `AddSkillByCardId`. EerieVillage `0ad1325` push 정합. **[2026-05-13 신규 2건]** (1) Player 피격 X fix — EnemyController.Update L387-396 영역 `IsGrounded` 조건 폐기 (PD 표현 "닿아도" = ground·공중 무관 피격 의도)·진단 Debug.Log 2종 revert. (2) Enemy HP 30~40 random — `Health.RandomMaxHPRange` (Vector2Int) Inspector 필드 신규·Awake 영역 random·`maxHearts` 자동 산정·Enemy.prefab Inspector `(30, 40)` PD 직접 설정. 본 PM 자성 #6 (PD Console 측정 결과 미수신 영역 가설 fix 시도·feedback_pm_root_diagnosis_priority 약한 위반). EerieVillage `b4847b1` push 정합. **[2026-05-13 재발 정정]** (1) Enemy HP 30~40 자동 fallback — Health.Awake 영역 RandomMaxHPRange 미설정 + EnemyController 검출 → 자동 random. PD Inspector 의존 폐기. (2) Player 피격 distance 기반 강화 + 진단 Debug.Log 재추가 — `VisualBounds.Intersects OR dist < 1.5f` 단일 조건·`[EnemyHit]` 진단·회수 의무. 본 PM 자성 #7 (feedback_pm_root_diagnosis_priority 위반 누적). EerieVillage `2efcd34` push 정합. **[2026-05-13 신규]** Enemy·Player 사망 모션 y -0.5 오프셋 — EnemyDeath·PlayerDeath Execute 영역 Animator death/hurt Trigger 직전 `transform.position.y -= 0.5` 적용·sprite 위로 떠 보이는 현상 정정·collider 영향 X. EerieVillage `18b2125` push 정합. **[2026-05-13 신규]** 스킬 선택 UI 아이콘 fallback — SkillCardSlot.Bind 영역 card.Icon null 시 동적 원 sprite (32×32 알파) + 속성별 색상 (Fire 주황·Frost 하늘·Dark 보라·Lightning 노랑·Physical 흰). _glowEffect 동심원 빛 효과 alpha 0.3. EerieVillage `32ab76f` push 정합. **[2026-05-13 신규 2건]** (1) 사망 모션 y -0.5 → -0.3 (EnemyDeath·PlayerDeath). (2) 게임 시작 시 파이어볼 투사체 정지·잔존 fix — ProjectileSpawner.Trigger 영역 `facing.sqrMagnitude<0.01f` 시 `Vector2.right` fallback. 원인: Player.Facing 영역 (0,0) 영역 → _direction = (0,0) → _speed × 0 = 정지. EerieVillage `56a4a36` push 정합. **[2026-05-13 신규]** 투사체끼리 통과 fix — Projectile.OnTriggerEnter2D 영역 동족 Projectile skip (Wall·Enemy 판정 이전). 원인: fallback GO default Layer 0 영역 → isWall=true → 양쪽 SelfDestruct. EerieVillage `ebd7086` push 정합. **[2026-05-13 신규 4건]** (1) Player 사망 사라지는 현상 fix — PlayerDeath 영역 `Rigidbody2D.simulated=false` (gravity 정지·낙사 차단). (2·3) 제자리 부활·부활 모션·2초 무적 깜박 — PlayerSpawn 영역 `Teleport` 폐기·`health.Resurrect()` 호출 (currentHP=maxHP·invulnerableUntil=2초·Animator resurrect Trigger)·Rigidbody simulated=true 복원·PlayerInvulnerabilityFlash 자동 깜박. (4) FX 잔상 safety cap 5초 — LaserSpawner fx Destroy 누락 추가·LightningStrike·MeleeArea·Projectile.AutoDestroy 영역 `Mathf.Min(lifetime, 5f)` cap. EerieVillage `3a672f0` push 정합. **[2026-05-13 컴파일 에러 fix]** PlayerSpawn.cs CS0246 — using UnityEngine 누락·첫 줄 추가. 본 PM 자성 #8 (신규 type 사용 시 namespace using 사전 검증 누락). EerieVillage `c052d78` push 정합. **[2026-05-13 신규 3건]** (1) Player 죽는 모션 X fix — Player.controller parameter "hurt" 부재 측정·`SetTrigger("hit")`·`updateMode=UnscaledTime`. (2) 부활 모션 중 움직임 fix — PlayerSpawn simulated 복원 폐기·EnablePlayerInput 영역 이전. (3) 투사체 잔상 진단 — `[Projectile][SelfDestruct]`·`[Projectile][OnDestroy]` Debug.Log·회수 의무. 본 PM 자성 #9 (Animator parameter 사전 측정 누락). EerieVillage `69a1805` push 정합. **[2026-05-13 NullReferenceException + 잔존 근본 fix]** ProjectileSpawner.Trigger 영역 collider isTrigger=true 활성 시점 vs Initialize 호출 시점 race → OnTriggerEnter2D 영역 `_runtime=null` NullReferenceException → SelfDestruct 미호출 → 영구 잔존. fix: OnTriggerEnter2D 영역 `_runtime/_data == null` defensive return + Update 영역 `_data == null` 시 즉시 SelfDestruct. 본 PM 자성 #10 (race condition 사전 측정 누락). EerieVillage `1437720` push 정합. **[2026-05-13 신규 3건]** (1) 사망 팝업 타이밍 fix — LevelUpManager.HandleLevelUp 영역 Player 사망 상태 시 _pendingLevels 영역 저장·Update 영역 IsAlive 회복 시 표시. (2) Player 사망 y -0.3 추가 (누적 -0.6). (3) 투사체 잔상 강화 + 진단 — Projectile.Update 영역 lifetime+0.5 backup·Initialize·Trigger 영역 진단 Log·회수 의무. EerieVillage `b1931af` push 정합. **[2026-05-13 근본 원인 fix]** 재시작 시 정지 투사체 누적 — Time.timeScale=0 (LevelUp 등) 영역 Time.time·Invoke 정지 영역 영구 잔존. fix: Projectile `_spawnTime = Time.unscaledTime`·Update 영역 unscaledTime lifetime check·Invoke 폐기·CancelInvoke 추가 안전. 본 PM 자성 #11 (timeScale 영향 사전 측정 누락). EerieVillage `705d943` push 정합. **[2026-05-13 진단 Log 회수]** PD "사라졌어" 정합 작동 확인 후 진단 Debug.Log 5종 revert (ProjectileSpawner·Projectile.Initialize·SelfDestruct·OnDestroy·EnemyHit). Projectile.Update lifetime backup·CancelInvoke 안전망 보존. feedback_pm_root_diagnosis_priority 정합. EerieVillage `41fa4e4` push 정합. **[2026-05-13 신규 2건]** (1) MeleeArea 실전 발사 연결 — SkillFireEvent.Execute switch 영역 MeleeArea case·CardId 분기 (A04·A_Laser·기타). (2) FX AutoDestroy unscaledTime — FxAutoDestroyUnscaled MonoBehaviour 신규 (Object.Destroy 영역 timeScale 영향 fix)·전수 변경·WaitForSecondsRealtime. 본 PM 자성 #12 (Unity 표준 API timeScale 영향 사전 측정 누락). EerieVillage `26b0666` push 정합. **[2026-05-13 신규]** A04 번개 충격 적 유무 무관 자동 발동 — LightningStrikeSpawner.Trigger 영역 candidates 0 시 Player 위치 fallback spawn. A05·A_Laser = 이미 Player 위치 기준 발동·정합. EerieVillage `ebedf6d` push 정합. **[2026-05-13 InvalidOperationException Input System fix]** ParticleGroupView (2).cs 영역 삭제 (Scenes 폴더 영역 비정상 .cs·미사용·StandaloneInputModule 동적 부착 코드)·ProjectSettings activeInputHandler 1→2 (Both 모드·호환). 본 PM 자성 #13. EerieVillage `b30976a` push 정합. **[2026-05-13 본 PM 자성 #14 + fix 정정]** PD 직접 자성 지적 — 본 PM 직전 미승인 `.cs` 삭제 영역 정정. PD 재배치 후 ParticleGroupView (2).cs UnityEngine.Input → InputSystem 전환·activeInputHandler 2→1 revert. EerieVillage `b23e00f` push 정합. **[2026-05-13 Phase A]** A12 정화의 빛 신규·A08 저주의 화살 이펙트 적용 — ActiveSkillData.CastFxPrefab 신규·ProjectileSpawner.Trigger 영역 CastFx spawn·SkillRuntimeFactory.AvailableCardIds 7종 확장. **Phase B 대기** (A06 독 늪·A11 정령불 신규 Effector). EerieVillage `5077f5d` push 정합. **[2026-05-13 Phase B]** A06 독 늪·A11 정령불 신규 Effector + 1키·2키 매핑 — PoisonSwampSpawner/Instance/PoisonedEnemyMarker·SpiritFireSpawner/Instance 신규·SkillFireEvent switch PlacementPersistent·Minion case 확장·TestSkillFireOn1to5 Category 분기 추가·A06·A11 .asset 신규·SkillRuntimeFactory 9종. PD Inspector Player.prefab Skill1·Skill2 drag&drop 필요. EerieVillage `f292eb4` push 정합. **[2026-05-13 Phase B FX 재생 fix]** ParticleSystem 명시 `Play(true)` 호출 추가·PoisonSwampInstance 영역 BoxCollider2D·Rigidbody2D 자식 GO 분리 (ParticleSystem root 영향 차단). EerieVillage `b1b476a` push 정합. **[2026-05-13 A11 frame 제어]** FX_Rotating shield Animator frame 제어 — intro 1~88·loop 89~105 반복·outro 106~169 (남은 frame). Animator.Play(STATE_HASH, 0, normalizedTime) 매 frame 호출. EerieVillage `ebd0808` push 정합. **[2026-05-13 A12·A08·전수 FX Play]** 4 Spawner + Projectile 영역 ParticleSystem.Play(true) 명시 호출 전수 적용 (직전 b1b476a 영역 PoisonSwamp·SpiritFire만 적용 영역 영역 영역 보완). EerieVillage `68843a8` push 정합. **[2026-05-13 A08 sprite 방향 fix]** ActiveSkillData.ProjectileAngleOffset (float Range -360~360) 신규·Projectile.Initialize 영역 angle 보정·A08.asset 180 (FX_PinkMagicArrow sprite left→right). EerieVillage `71c3b7d` push 정합. **[2026-05-13 A08 FX 진단]** A08.asset GUID 정합·코드 정합 측정. PD 보고 영역 실측 진단 Debug.Log 추가 (회수 의무). EerieVillage `aa6cef1` push 정합. **[2026-05-13 CS1056 fix]** ProjectileSpawner.cs interpolated string `\"NULL\"` escape 영역 컴파일 에러·ternary 결과 변수 분리 fix. 본 PM 자성 #15 (Edit 후 컴파일 사전 검증 누락). EerieVillage `9879425` push 정합. **[2026-05-13 fileID 잘못된 측정 정정·자성 #16]** PD Inspector 측정 결과 영역 본 PM .asset 영역 fileID 영역 자식 GameObject 영역 매핑 영역. `grep -m 1` 영역 첫 GameObject 영역 = root 영역 영역 X. A08·A06·A12 .asset 영역 fileID 일괄 정정 (FX_PinkMagicArrow_Hit·FX_PinkArrow_Shoot·FX_Venom_Spray·FX_Icelight_Seal). 올바른 측정 = `awk m_Name + m_Father=0 정합`. EerieVillage `b26eb42`·`447ea92` push 정합. **[2026-05-13 CastFx 방향 + 진단 회수]** CastFx Instantiate 영역 facing+ProjectileAngleOffset+FxRotation 적용 (sprite 반대 방향 정정)·진단 Debug.Log 3종 revert. EerieVillage `7ad3319` push 정합. **[2026-05-13 A08 spawn 끝점·grace]** A08.asset OffsetDistance.x=1.5 (캐스팅 끝 spawn)·Projectile.OnTriggerEnter2D 영역 0.1초 grace 추가 (Hit FX Player 위치 회피). EerieVillage `eab215d` push 정합. **[2026-05-13 ScalingMode Hierarchy 전수]** 모든 fx spawn 영역 ParticleSystem.MainModule.scalingMode = Hierarchy 설정 (HitFxScale 정합 적용·7 파일 전수). EerieVillage `6ed6efe` push 정합. **[2026-05-14 자연 fade SelfDestruct]** Projectile.SelfDestruct 영역 즉시 Destroy 영역 → ParticleSystem Stop(emission)·Collider/박스 disable·_speed=0·0.5s 후 Destroy·FADE_START_RATIO 0.85. 발사 영역 영역 영역 trail 자연 연속. EerieVillage `2ee5084` push 정합. **[2026-05-14 A08 캐스팅 제거·적 조준]** A08.asset OffsetDistance.x=0·CastFx=null·TargetEnemyOnFire=1·ActiveSkillData.TargetEnemyOnFire 신규·ProjectileSpawner.Trigger 영역 nearest enemy 방향 발사. 벽·발판 관통 X 영역 = Projectile.Update Layer 0·16 OverlapPoint 영역 정합. EerieVillage `55ee4f3` push 정합. **[2026-05-14 HitFx sortingOrder·적 조준 하단]** 모든 hit fx (Projectile·LightningStrike·MeleeArea·Laser) Renderer.sortingOrder += 100 (Enemy 영역 위)·ProjectileSpawner TargetEnemyOnFire 영역 toEnemy.y -= 0.5 (hitbox 영역 영역 영역 적중). EerieVillage `eb33e64` push 정합. **[2026-05-14 적 조준 중간 보정]** toEnemy.y -= 0.5 → 0.25 (이전·1차 중간·너무 하단 정정). EerieVillage `b52c99d` push 정합. | **진행중** | 신규 `Assets/Scripts/MyUI/SkillInventoryHUD.cs` (OnGUI 좌상단·장착 액티브 DisplayName·Lv·CooldownRemaining/EffectiveCooldown·패시브 카운트). PlayerController.Awake 자동 부착. 보강: ProjectileSpawner fallback prefab에 SpriteRenderer + 동적 흰색 원 sprite + 속성별 색상 (Fire 주황·Frost 하늘·Dark 보라·Lightning 노랑·Physical 흰). Unity 기본 자원 활용 — Texture2D 동적 생성 16×16 알파 원. **[이펙트 개선 완료 2026-05-13]** (PD 지시 "이펙트 개선작업은 완료처리"). 본 세션 (`cranky-wescoff-e855b0`) 누적: (1) 5 스킬 통합 + 1~5 키 발사 시스템 — A02·A04·A05·A_Laser·A13 (EerieVillage `2ebf313`). (2) Inspector 즉시 반영 필드 확장 — HitboxSize·OffsetDistance(Vector2)·OffsetXY·FxRotation·HitFxScale·DamageFrameDelay·EnableRepeatDamage·MaxHitCount·RepeatFrameInterval. (3) hit 모션 + flash 연출 (붉은색·alpha 50%·1 frame) — Animator self-loop transition + Health.DecrementBypassInvulnWithHit. (4) Scene 잔존 박스·FX 6개 cleanup + HideFlags.DontSave 8 spawn 지점 (EerieVillage `60e28e3`) — Edit Mode execute_code 측정 시 Scene 오염 방지 표준 확립. (5) FxRotation 박스 미적용 분리 (EerieVillage `ea7d32f`) — 박스(판정) = facing 만 · 이펙트(시각) = facing + FxRotation. 4 case 검증 (facing R/L × FxRotation 0/90 박스 무반응·facing 좌/우 정확 반전). (6) A05 좌우 베기 이펙트 Player 동조 (EerieVillage `f6c6eb5`) — MeleeAreaSpawner.SetParent(true) 추가·Player 전진 시 이펙트 밀림 정정 (Δ+2.0 동조 측정). 양 레포 push 정합. | — | **이펙트 개선 영역 = 완료 처리.** HUD·Icon UI·Layer Lab 카드 정합 등 잔여 사항은 PD 후속 결정 대기. 인수인계서: `공유/조직공지/2026-05-13_BT12-Dev_세션종결인수인계.md`. **[이펙트 작업 완성 확정 2026-05-14]** (PD 발화 "스킬 이펙트 작업은 완성이야. 임의로 투사체 판정 범위나 크기 등이 바뀌지 않도록 지금 상태를 잘 기록해"). 본 PM SOT 신설: `프로젝트/EerieVillage/개발/spec/스킬_이펙트_확정_v1.md` — 13 활성 스킬 (A01·A02·A03·A04·A05·A06·A08·A11·A12·A13·A14·A15·A_Laser) 핵심 필드 표 + 박스↔이펙트 분리 원칙 + EerieVillage stamp `1a1de0c`. **변경 금지 원칙**: PD 직접 명시 지시 없이 임의 변경 금지. 변경 시 SOT §4 갱신 + commit + PD 보고 의무. 본 PM·차기 세션 PM 모두 본 SOT 준수. | | BT12-Dev-Death | 2026-05-09 | **스킬 습득 후 사망 버그 지시** — PD 직접 발화: "스킬 습득 후 일정시간이 지나면 왜 플레이어가 갑자기 죽는거지? 버그를 수정해줘." | **완료 2026-05-10 (PD 정합 확인)·아카이브 이동 영역** | (1) Projectile.OnTriggerEnter2D에 PlayerController 명시 차단 (defensive proxy·자기 hit 차단). (2) Health.Decrement·DecrementSilent·Die에 Debug.Log + System.Environment.StackTrace 추가 (사망 호출자 추적). **(3) 근본 fix 1 2026-05-09 EerieVillage `b37b4a6`**: HealthIsZero.Execute에 sender 검증 가드 추가 (PlayerController 보유 Health만 PlayerDeath 발화). **인수인계서 가설(EnemyController patrol → PlayerEnemyCollision) 부정** — Player Decrement 로그 부재. **근본 원인 1**: HealthIsZero.Execute가 health sender 검증 없이 무차별 Schedule() 발화. BT12-Dev Phase 2-B 투사체가 사상 처음 Enemy.Health.Decrement → Enemy의 HealthIsZero가 PlayerDeath 직결 노출. **PD 결정 (2026-05-09) "1 즉시 적용해"** — A안 1줄 fix 즉시 적용. pm-auditor Pass + Minor 1 (매니페스트 등록 정정 적용) + Improvement 2. **(4) 근본 fix 2 2026-05-09 EerieVillage `33eaa55`**: ProjectileSpawner fallback Scene GameObject 잔존 fix. **(10) 근본 fix 8 + 임시 fix 2026-05-10 EerieVillage `6a825fc`** (PD 지시 3건·MCP 자율 진단·검증 정합): PD 보고 — 투사체 영역 적이 죽지 않음·경험치 X·레벨업 X. PD 지시 — (1) 기본 공격력 5 고정 (임시) (2) 죽는 모션 + 소멸 (3) 경험치 + 레벨업. 본 PM MCP 자율 진단 — execute_code 영역 PlayerSkillInventory.AddSkillByCardId 영역 카드 추가 + Player·Enemy 위치 강제 + Tick 영역 자동 발사 영역 → Console 영역 `[Health@Enemy] Decrement(damage=4) hp 4→0` 출력 정합 (투사체 hit 정합) **그러나 [ExperienceSystem] X·[EnemyDeath] X** → **Projectile.cs 영역 Schedule 호출 누락** 확정. **근본 fix 2종**: (1) damage Mathf.Max(_runtime.CalculateEffectiveDamage(), 5) — 임시 5 하한 (PD 지시) (2) Enemy hp 0 도달 영역 Schedule().enemy = enemy 추가 — AttackHitbox.cs:70~76 패턴 정합. **MCP Play 검증**: damage=5·hp 4→0·ExperienceSystem.OnEnemyKilled·GainXP·LEVEL UP Lv.1→2→3→4·SkillSelectionUI Show·카드 확정 정합. **(9) 근본 fix 7 2026-05-10 EerieVillage `f501960`** (PD "MCP 활용해서 네가 직접 체크해" + 본 PM MCP 자율 진단·fix·검증·PD 자성 #13): 본 PM Inspector·Animator·Console MCP 직접 점검 영역. Enemy.controller `controller_get_info` 영역 — parameters: velocityX·velocityY·hurt·death·grounded · Idle/Run/Hurt → Death/Hurt **transition X** 영역 발견. Schedule 직접 호출 영역 검증 — `enabled=false`·`collider=false`·`simulated=false` 적용 영역 — **Animator state = Baddie-Idle/Run 영역 영역**. 추가 진단 — `Time.timeScale = 0` (LevelUp 카드 선택 모드) + Animator updateMode = Normal → Animator.Update 정지 → death Trigger 호출 영역 transition X. **근본 fix 2종**: (A) Enemy.controller transition 5 추가 (Idle→Death·Idle→Hurt·Run→Death·Run→Hurt·Hurt→Death·`manage_animation controller_add_transition` 직접) (B) EnemyDeath.cs `animator.updateMode = AnimatorUpdateMode.UnscaledTime` 추가 → timeScale 무관 영역 Animator 정합 영역. 검증 — anim.SetTrigger("death") + anim.Update(0.5f) → Baddie-Death 진입 정합. 진단 Debug.Log 회수 (Projectile 8·AttackHitbox 1·EnemyDeath 1). **(2026-05-10 세션 종결)** — 인수인계서 `공유/조직공지/2026-05-10_BT12-Dev_세션종결인수인계.md`. 양 레포 push 정합 — EerieVillage `1ef1989`. 본 세션 commit 누적 21건. 영역 영역: 사거리 차이 PD 검증·Hurt/Death animation·Wall Layer 영역. **(8) 진단 도구 fix 6 2026-05-10 EerieVillage `d6764ce`** (PD A+B 결정·feedback_pm_root_diagnosis_priority 2차 적용): PD Console 분석 결과 본 PM 가설 5회 누적 부정확 자성. 핵심 발견 — 투사체 hit X·**AttackHitbox(BT7-Dev VS 순수형 자동 근접)** 영역 hit (t=4.15·t=4.66 hp 4→1·1→0). t=5.35 [Projectile][Enter] other=Enemy → Enemy Collider 활성 → **EnemyDeath.Execute 호출 X 영역 확정**. AttackHitbox.cs:75 `Schedule` 호출 영역 Execute 영역 호출 영역 의문 → 진단 Debug.Log 2종 추가: [AttackHitbox][Schedule] (col·enemy·hp·t)·[EnemyDeath][Execute] (enemy·collider.enabled·t). pm-auditor 통과 + Minor 1 (회수 트리거 명시) + Improvement 1 (_collider 동시 캡처) 수용. 회수 의무: PD 사망 원인 확정 직후 본 PM revert commit. **(7) 진단 도구 fix 5 2026-05-09 EerieVillage `d27a63f`** (PD A안 결정·feedback_pm_root_diagnosis_priority 영역 적용): PD 4차 보고 "여전히 적에게 제대로 피격되지 않고 통과하고 있어" → 본 PM 가설 4회 누적 부정확·회귀 1회 → 가설 즉시 중단·실측 우선·진단 Debug.Log 영역 추가. Projectile.OnTriggerEnter2D 영역 8 분기 진입·return·Hit 시점 영역 [Projectile][...] prefix 통일 영역 → PD Play Console 영역 호출 여부·other 정보·Layer·EnemyController·Health 영역 정확 진단 → 근본 원인 확정 후 fix. 회수 의무 명시 (PD Console 수령 + 근본 fix 후 일괄 제거). pm-auditor 통과 (조건부) + 권고 4종 (prefix 통일·가설 X·회수 명시·PD 안내) 수용. **(6) 회귀 정정 fix 4 2026-05-09 EerieVillage `9eebbec`** (C3 자진 고지): fix 3 영역 Kinematic Rigidbody2D 추가가 회귀 유발 — PD 3차 보고 "여전히 적이 플레이어의 투사체에 피격되지 않아". **근본**: Enemy = KinematicObject 상속 영역 Kinematic Rigidbody2D → Projectile Kinematic 영역 추가 시 Kinematic vs Kinematic + useFullKinematicContacts=false (기본값) → OnTriggerEnter2D 발화 X 영역 회귀. **본 PM 자성 #11 (헌법급)**: C39 위반·KinematicObject.cs:76 영역 사전 Read X. **fix**: ProjectileSpawner.CreateFallbackProjectile 영역 Rigidbody2D 영역 5 라인 제거 → `33eaa55` 시점 Static vs Kinematic Trigger 발화 정합 복원 (DebuffStackLimit 정정 영역 그대로 유지). **헌법급 feedback `feedback_new_code_existing_system_dependency_unmeasured` 신설** (신규 코드 영역 기존 시스템 의존성 미실측 금지·재발 차단 3 단계 의무). **(5) 근본 fix 3 2026-05-09 EerieVillage `fe65592`**: PD 2차 재검증 결과 ("판정 X 또는 효과 X") → 본 PM 진단 — **결함 1**: A01·A02·A03·A14·A15 영역 DebuffStackLimit 무차별 3 적용 (본 PM Phase 2-C placeholder 무차별 채움) → StatusApplier 가드 통과 → 의도 외 DebuffStack 트리거. **결함 2**: ProjectileSpawner.CreateFallbackProjectile Rigidbody2D 부재 → Trigger 판정 안정성 부족. **PD 결정 "3 동시 진행해"** — 옵션 3 양 결함 동시 적용. 5 asset DebuffStackLimit 3→0 + Rigidbody2D Kinematic 추가 (gravityScale 0·CollisionDetectionMode2D.Continuous). pm-auditor Conditional Pass + **Major 1 (헌법급 feedback `feedback_scriptable_object_field_blanket_fill.md` 신설·C39-10 위반·근층 원인 명문화)** + Improvement 2. **PD 1차 재검증**: Player 사망 X 정합·**잔존 투사체 1개 영구 노출** (PD 첨부 이미지). **근본 원인 2**: `Resources/Skills/Projectiles/Default` prefab 부재 → `LoadProjectilePrefab` fallback이 `new GameObject`로 Scene 영역 GameObject 생성·반환 → `Object.Instantiate(prefab,...)`가 이를 prefab으로 사용 → 사본은 정상 SelfDestruct·**원본 Scene GameObject는 Initialize 미호출·영구 잔존**. **fix (옵션 J)**: LoadProjectilePrefab은 Resources prefab만 반환·부재 시 null. Trigger 영역 prefab null 시 `CreateFallbackProjectile` 직접 호출 (Instantiate X·자기 자신 발사체). pm-auditor Pass + Minor 1 (line 65 주석 정합 영역 후속) + Improvement 1. | — | **PM 후속**: PD 2차 Play 재검증 (적 처치 후 Player 정상 + 투사체 발사 후 정상 SelfDestruct + 잔존 투사체 0건) → 정상 시 BT12-Dev-Death 완료 아카이브 이동. Enemy 사망 처리 발화 경로 후속 검증 (이전 Improvement 2 영역). | diff --git a/프로젝트/EerieVillage/개발/spec/맵_시스템_설계_v1.md b/프로젝트/EerieVillage/개발/spec/맵_시스템_설계_v1.md new file mode 100644 index 0000000..76535f2 --- /dev/null +++ b/프로젝트/EerieVillage/개발/spec/맵_시스템_설계_v1.md @@ -0,0 +1,1160 @@ +--- +type: 설계_문서 +scope: 맵_시스템 (절차 생성 + 시각 시뮬레이터 + 리소스 카탈로그) +author: 개발팀장 (dev-team-lead) +date: 2026-05-18 +version: v1.0 (BT13-Dev-Map Phase 1 — 단일 SOT) +project: EerieVillage (기묘한 고을 : 조선퇴마뎐) +phase: BT13-Dev-Map Phase 1 (개발팀장 Opus 설계) +data_source: | + BT5-Dev 인수인계 2026-05-07·2026-05-08 (발판 시스템 BT47·BT75·몬스터 BT76~BT109)· + E:/EerieVillage/Assets/Scripts/Mechanics/{KinematicObject,PlayerController,EnemyController,GameOptimizer,SpawnPoint,MonsterRandomizer}.cs· + E:/EerieVillage/Assets/Scripts/Model/PlatformerModel.cs· + E:/EerieVillage/Assets/Prefabs/{Player,Enemy,Enemy_M001~M006}.prefab· + E:/EerieVillage/Assets/Tiles/{TileFloating*,TileGround*,cloud,fence,ShortBuilding,TallBuilding,MidgroundFiller}.asset· + E:/EerieVillage/ProjectSettings/Physics2DSettings.asset· + 프로젝트/EerieVillage/기획/05_스테이지_구조_초안.md v0.1· + 프로젝트/EerieVillage/기획/level/01_스테이지_구조.md v0.1· + 프로젝트/EerieVillage/개발/spec/스킬_시스템_설계_v1.md v1.0 +status: Phase 1 설계 완료 — Phase 2 코드 구현 분할 권고 + PD 결정 대기 안건 11건 (§15 정합·2026-05-18 PM 정정·dev-team-lead 자기 검증 누락 보완) +--- + +# 맵 시스템 설계 v1 (BT13-Dev-Map) + +## §1. 요구 분석 + PD 결정 4건 정합 확인 + +### 1-1. PD 핵심 요구 (2026-05-18 원문 7항) + +> "이제 나는 우리 게임의 맵을 제작하고 싶어. +> * 일반적인 플랫포머 게임의 맵 제작 방식을 고려해 맵을 만들고 싶어. +> * 하지만 맵의 길이만 지정하면, 랜덤으로 자동으로 생성하는 형태의 맵 시스템을 만들고 싶어. +> * 맵에는 자동으로 몬스터가 등장하게 될 생성 포인트(거점)이 배치되어야하고, 플레이어가 시작하는 스타트 포인트도 존재해야 해. +> * 몬스터는 항상 생성 포인트 주변에서 생성되며, 현재 만들어진 몬스터 이동 패턴을 활용해서 동작하기를 바래. +> * 시뮬레이션을 시각적인 정보로 미리 만들어질 맵의 구조를 보고 결정할 수 있는 형태면 좋겠어. +> * 사용할 맵 리소스를 자유롭게 추가할 수 있도록 리소스를 등록하는 형태의 기능이 있으면 좋겠어. +> * 게임에 등장하는 발판(충돌 영역 포함)의 배치 등이 플레이어가 점프로 이동 가능한 높이나 거리에 맞게 설계되면 좋겠어. (플랫포머 게임의 자연스러운 레벨디자인) +> * 바닥의 길은 사용자가 일일이 수정하지 않아도 충돌 영역이 자연스럽게 적용되면 좋겠어." + +### 1-2. PD 추가 결정 4건 (PM 사전 명세 안건 답변) + +| # | 안건 | PD 결정 | 본 설계 반영 | +|---|------|---------|------------| +| 1 | 시각 시뮬레이터 | Unity Editor Window 1순위 · 어려우면 Scene 미리보기 fallback | §10 — EditorWindow 채택 (실측 결과 1순위 가능) | +| 2 | 맵 리소스 단위 | 양쪽 다 — 배경=Tile, 일부 기믹=Prefab | §5 — Tile/Prefab 이원 분리 | +| 3 | 랜덤성 | 매번 완전 랜덤 (Seed 입력 X) | §4 — `UnityEngine.Random` 매 생성 새 시드 | +| 4 | 거점 밀도 | 맵 길이·비율을 옵션으로 미리 지정 → 옵션 값 동작 | §8 — `MapGenerationConfig.SpawnDensity 0.0~1.0` | + +### 1-3. 헌법 제1원칙 정합 + +- **①** AI 에이전트 활용 — 개발팀장 Opus 설계, 클라이언트팀 Sonnet 구현 (C49) +- **②** 경험 축적 — BT5-Dev 발판 시스템·BT12 스킬 시스템 자산 전부 계승 +- **③** 허위 보고 금지 — §2 사전 실측 영역에서 모든 추정 X·Read 결과만 기재 +- **④** 조직 단위 운영 — 본 단계 Phase 1 단독·Phase 2 분할 권고는 §13 +- **⑤** 세션 연속성 — 본 설계서 = 단일 SOT, Phase 2 어떤 세션에서 진입해도 정합 + +--- + +## §2. 사전 실측 결과 (C39-10 의무 — 위반 #1~#7 재발 차단) + +### 2-1. KinematicObject (`E:/EerieVillage/Assets/Scripts/Mechanics/KinematicObject.cs`) + +| 항목 | 실측값 | 본 설계 활용 | +|------|--------|------------| +| `minGroundNormalY` | 0.65f | 발판 경사 한계 — 본 설계 평탄 발판 고정 | +| `gravityModifier` | public 1f (Player/Enemy prefab) | 점프 물리 식 계산 입력값 | +| `Bounce(float)` | velocity.y 직접 set | 본 설계 미사용 | +| `Teleport(Vector3)` | body.position + velocity *=0 | 본 설계 Player Spawn 시 활용 | +| `body.Cast(contactFilter)` | hitBuffer[16] · contactFilter Layer mask 적용 | Drop-Through 발판 통과 메커니즘 SOT | +| `velocity.x = targetVelocity.x` | FixedUpdate 매 frame 덮어씀 | 직접 set 1 frame만 효과 | +| `ignoreCollisions` (2026-05-15) | 날으는 몬스터용·body.Cast skip | 본 설계 무관 (M002 박쥐 영역) | + +### 2-2. PlayerController (`E:/EerieVillage/Assets/Scripts/Mechanics/PlayerController.cs`) + +| 항목 | 실측값 | +|------|--------| +| `maxSpeed` | 3 (Player.prefab line 63) — BT12 Phase 2-D 영역 7→3 정정 | +| `jumpTakeOffSpeed` | 7 (Player.prefab line 64) | +| `JUMP_THROUGH_LAYER` | const 16 | +| `JUMP_ASCENT_DURATION` | const 0.4f (점프 ascending mask OFF) | +| `DROP_THROUGH_DURATION` | const 0.3f (Down+Jump Drop-Through mask OFF) | +| `UpdateContactFilterForDropThrough` | footHit Raycast 3점(좌·중·우)·nearApex+horizontalIntent 영역 강제 Drop-Through | +| `Awake()` 자동 부착 | PlayerInvulnerabilityFlash·ResurrectPromptUI·PlayerProgression·PlayerSkillInventory·SkillInventoryHUD | + +### 2-3. PlatformerModel (`E:/EerieVillage/Assets/Scripts/Model/PlatformerModel.cs`) + +| 항목 | 실측값 | +|------|--------| +| `jumpModifier` | 1.5f | +| `jumpDeceleration` | 0.5f (release 시 velocity.y × 0.5) | + +### 2-4. Physics2D (`E:/EerieVillage/ProjectSettings/Physics2DSettings.asset`) + +| 항목 | 실측값 | +|------|--------| +| `m_Gravity.y` | -9.81f | +| `m_VelocityIterations / PositionIterations` | 8 / 3 | + +### 2-5. 점프 도달 한계 산출 (실측 수치 기반) + +PlayerController.ComputeVelocity 영역: +``` +velocity.y = jumpTakeOffSpeed × model.jumpModifier = 7 × 1.5 = 10.5 m/s +``` + +KinematicObject.FixedUpdate 영역 gravity 적용: +``` +velocity.y -= 9.81 × gravityModifier × dt = 9.81 × 1 × dt +``` + +| 산출 | 공식 | 값 | +|------|------|---| +| 최대 점프 높이 (full hold) | H_max = v0² / (2g) = 10.5² / (2 × 9.81) | **5.62m** | +| 점프 정점 도달 시간 | t_up = v0 / g = 10.5 / 9.81 | **1.07s** | +| 점프 왕복 시간 (착지) | t_round = 2 × t_up | **2.14s** | +| 점프 중 수평 최대 거리 | D_max = maxSpeed × t_round = 3 × 2.14 | **6.42m** | +| Stop Jump (release) 시 ascending 절반 cap | v_after = 0.5 × v_now → H_partial ≈ H_max × 0.25 | **~1.4m (조기 release 영역)** | +| 안전 점프 거리 (90% margin) | D_max × 0.9 | **~5.78m** | +| 안전 점프 높이 (90% margin) | H_max × 0.9 | **~5.06m** | + +**본 설계 발판 배치 룰 (§6)에 이 수치 직접 적용**. + +### 2-6. EnemyController (`E:/EerieVillage/Assets/Scripts/Mechanics/EnemyController.cs`) + +| 항목 | 실측값 | 본 설계 활용 | +|------|--------|------------| +| `patrolMinRange / patrolMaxRange` | 5 / 10 (Enemy.prefab) — 본 EC.cs default 50/75는 prefab override됨 | Spawn Point 영역 좌우 ±10m patrol 영역 확보 의무 | +| `cliffCheckDistance / cliffCheckDepth` | 1.0 / 2.0 | 발판 끝단 cliff 검출 — Spawn 발판 폭 >2m 필수 | +| `groundLayerMask` | (1<<0) \| (1<<16) — Layer 0 Level + Layer 16 AutoForeground | Spawn 발판 Layer 0 또는 16 | +| `fallThreshold` | 1.0f → startY - 1.0 미만 시 시작 위치 텔레포트 | 떨어진 Enemy 자동 복귀 (BT102) | +| `IsFlying` | controller name "M002" 매칭 시 true · cliffCheck skip | 본 설계 M002는 공중 spawn | +| `_isInitialized` | Start 시점 MeasureSafeWalkDistance 완료 후 true | Enemy spawn은 Scene 로드 후 1 frame 대기 의무 | +| `MeasureSafeWalkDistance` | Tilemap WorldToCell + HasTile cell 연속 + 위·아래 1 cell 인접 (계단 정합) | Spawn 발판 Tilemap 등록 필수 | +| `_cachedPlayer` collide | distance < 1.5f or VisualBounds.Intersects → Decrement (i-frame 외) | 본 설계 무관 (Enemy 동작 SOT) | + +### 2-7. GameOptimizer (`E:/EerieVillage/Assets/Scripts/Mechanics/GameOptimizer.cs`) — 본 설계 결정적 영향 + +| 동작 | 본 설계 영향 | +|------|-------------| +| `Init()` BeforeSceneLoad — targetFrameRate 60·Physics2D.IgnoreLayerCollision(13,14) | 본 설계 무관 (이미 적용) | +| `SetupJumpThroughPlatforms()` AfterSceneLoad — 모든 Collider2D 분류 | **본 설계 절차 생성 Tilemap은 본 hook 진입 전 완료 의무** | +| Level Tilemap(name="Level") = Layer 0 보존 | 본 설계 지면 Tilemap 영역 name="Level" 강제 | +| 그 외 비-trigger Collider2D = Layer 16 강제 | 본 설계 공중 발판 Tilemap name≠"Level" 시 자동 Layer 16 | +| `Foreground` GameObject = 가림막 시각만·TilemapCollider 제거 | 본 설계 절차 생성 시 "Foreground" name 회피 | +| `AutoForeground` 자동 생성·Grid 자식 | 본 설계는 Level/AutoForeground 직접 생성 OR GameOptimizer 자동 분류 위임 (§7 결정) | +| Level Tile worldY ≥ playerY+1.5 OR 작은 공중 발판(가로≤8+위아래 빈) → AutoForeground 이동·Sprite 강제 | **본 설계 = 두 옵션** (A) 절차 생성기에서 즉시 분리 (B) Level 단일 Tilemap 배치 후 GameOptimizer 위임 | +| TileGround prefix 제외 | 본 설계 지면 Tile name "TileGround*" 강제 영역 | + +### 2-8. Tile 자산 (`E:/EerieVillage/Assets/Tiles/`) + +| Tile | m_ColliderType | 용도 | +|------|---------------|------| +| TileGround.asset | 1 (Sprite) | 지면 | +| TileGroundTop.asset | 1 | 지면 표면 | +| TileGroundDark.asset | 1 | 어두운 지면 변형 | +| TileFloatingLeftEdge.asset | 1 | 공중 발판 좌측 끝 | +| TileFloatingTileMiddle.asset | 1 | 공중 발판 중간 | +| TileFloatingRightEdge.asset | 1 | 공중 발판 우측 끝 | +| cloud.asset | 1 | 공중 발판 변형 (구름) | +| fence.asset | (확인 보류 — 기획팀 장식 영역) | 배경 | +| ShortBuilding/TallBuilding/MidgroundFiller.asset | (배경) | 배경 영역 | + +**전 Tile m_ColliderType=1(Sprite) 사전 확정** → 본 설계 §7 자동 충돌 적용 핵심 근거. + +### 2-9. Prefab (`E:/EerieVillage/Assets/Prefabs/`) + +| Prefab | m_Layer | 본 설계 활용 | +|--------|---------|------------| +| Player.prefab | 13 | 1 인스턴스 (Start Point Spawn) | +| Enemy.prefab | 14 | (구) MonsterRandomizer 영역 random 6종 | +| Enemy_M001_Wolf~M006_Spider.prefab | 14 (추정) | 본 설계 SpawnPoint별 개별 prefab 선택 OR Enemy.prefab + MonsterRandomizer 위임 (§9) | + +### 2-10. Scene·기획 정합 (`프로젝트/EerieVillage/기획/level/01_스테이지_구조.md` v0.1) + +| 기획 영역 | 본 설계 정합 | +|---------|------------| +| 5종 스테이지 (마을 ↔ 1-5) | 본 설계 절차 생성기는 **스테이지별 옵션 카탈로그** 제공 (§11) | +| 3단 구성 (도입·전개·보스 방) | 본 설계 §4 청크 분할 권고: Intro/Mid/BossPre 3 영역 + Boss 방은 별도 수동 Scene | +| 횡스크롤 길이 5~10분 | 본 설계 맵 길이 옵션 = Tile 단위 길이 (§15 PD 결정 안건) | +| **§5 자동 생성 vs 수동 배치 — "전체 수동 배치 + 구간 2 적 배치 소규모 셔플" 채택** | **PD 신규 지시(2026-05-18) = 본 기획 결정 OVERRIDE — "맵의 길이만 지정하면, 랜덤으로 자동 생성"** → 기획팀 후속 정합 안건 (§15) | +| §10 §10-2 "낙하 함정" 등 지형 기믹 — 개발팀 C11 판단 이관 | 본 설계 §11 MapResourceCatalog → 기믹 Prefab 등록 영역 | + +### 2-11. BT12 스킬 시스템 영향 평가 (`프로젝트/EerieVillage/개발/spec/스킬_시스템_설계_v1.md` v1.0) + +| BT12 영역 | 본 설계 영향 | +|----------|------------| +| PlayerSkillInventory·ActiveSkillRuntime·6종 Effector(Lightning·Melee·Spirit·Poison·Laser·Projectile) | **영향 없음** — 본 설계는 맵 절차 생성만, Player 컴포넌트는 PlayerController.Awake 자동 부착 그대로 | +| 스킬 효과 충돌 영역 (Effector → Health.Decrement) | 본 설계 영향 없음 — Enemy.prefab Health 그대로 | +| Enemy ATK/HP | 본 설계 영향 없음 — Enemy.prefab 그대로 spawn | +| MonsterRandomizer (6 controller random) | 본 설계 § 9 Spawn 영역에서 활용 가능 (옵션 1: Enemy.prefab spawn → Awake에서 Random / 옵션 2: 본 설계 SpawnPoint config에서 특정 M00N 강제) | + +### 2-12. 기존 MapGenerator/Spawn 시스템 0건 사전 확정 + +`grep MapGenerator|RandomMap|ProceduralMap|MapBuilder E:/EerieVillage/Assets/Scripts` → 0건. +`grep SpawnPoint` → 1건 (`Mechanics/SpawnPoint.cs` = 11줄 빈 marker 클래스). + +→ 본 설계 = **완전 신규 시스템 도입**. 기존 코드와 충돌 없음. GameOptimizer·EnemyController·PlayerController 영역과 인터페이스 정합만 의무. + +### 2-13. Editor 폴더 영역 + +`E:/EerieVillage/Assets/Editor/` 영역 GitAutoSync만 존재 → **EditorWindow 신규 도입 깨끗** (Phase 2-C 영역). + +--- + +## §3. 아키텍처 4계층 + +``` +┌────────────────────────────────────────────────────────────────┐ +│ 계층 4: 시각 시뮬레이터 (Editor only) │ +│ - MapPreviewWindow (EditorWindow) │ +│ · GUI 영역 옵션 입력 + Generate 버튼 + 미리보기 캔버스 │ +│ · Handles.DrawLine·DrawSolidArc → 발판·SpawnPoint·점프 영역 │ +│ - MapSceneApplier (Scene 적용 버튼) — Phase 2-C │ +└────────────────────────────────────────────────────────────────┘ + ▲ 호출 +┌────────────────────────────────────────────────────────────────┐ +│ 계층 3: 절차 생성기 (Runtime + Editor 양립) │ +│ - MapGenerator (정적 메서드 또는 MonoBehaviour) │ +│ · Input: MapGenerationConfig (옵션 SO 또는 struct) │ +│ · Output: MapBlueprint (in-memory 데이터) │ +│ - PlatformLayoutPlanner (§6 발판 배치 룰) │ +│ - SpawnPointPlanner (§8 거점 배치) │ +│ - TerrainPlanner (§7 바닥 자동 충돌) │ +└────────────────────────────────────────────────────────────────┘ + ▲ 참조 +┌────────────────────────────────────────────────────────────────┐ +│ 계층 2: 데이터 SOT (ScriptableObject) │ +│ - MapResourceCatalog (Tile·Prefab 카탈로그) │ +│ - MapGenerationConfig (옵션·길이·밀도) │ +│ - PlatformerJumpProfile (실측 점프 수치 SOT) │ +│ - SpawnRuleProfile (Enemy spawn 규칙) │ +└────────────────────────────────────────────────────────────────┘ + ▲ 입력 +┌────────────────────────────────────────────────────────────────┐ +│ 계층 1: 실행·런타임 적용 │ +│ - MapApplier (Scene 적용 — Tilemap.SetTile + Instantiate) │ +│ - Player Start 배치 + Enemy SpawnPoint 인스턴스 생성 │ +│ - GameOptimizer.SetupJumpThroughPlatforms() 진입 전 완료 의무 │ +└────────────────────────────────────────────────────────────────┘ +``` + +### 3-1. 데이터 흐름 + +``` +[PD] [본 시스템] + │ │ + ├─ MapResourceCatalog SO 영역 등록 ───────►│ Tile·Prefab 풀 + │ (Editor·자유 추가) │ + │ │ + ├─ MapGenerationConfig 옵션 지정 ─────────►│ + │ · LengthTiles=120 │ + │ · SpawnDensity=0.5 │ + │ · StageProfile=Stage1 │ + │ ▼ + │ [MapGenerator.Generate(config)] + │ │ + │ ▼ + │ [MapBlueprint] + │ · TerrainTiles[] + │ · PlatformTiles[] + │ · SpawnPoints[] + │ · StartPoint + │ · Goal + │ │ + ├─ MapPreviewWindow [Generate] ────────────┤ in-memory preview + │ (시각 검토) ◄───── DrawHandles ──────────┤ + │ │ + ├─ [Apply to Scene] ──────────────────────►│ MapApplier + │ │ · Tilemap.SetTile + │ │ · Instantiate(Enemy/Player) + │ ▼ + │ [Scene 영역 완성] + │ │ + │ ▼ + │ (Play) GameOptimizer.AfterSceneLoad + │ │ + │ ▼ + │ EnemyController.Start → patrol +``` + +--- + +## §4. 절차 생성 알고리즘 + +### 4-1. 입력 + +```csharp +[CreateAssetMenu(menuName = "EerieVillage/Map/Generation Config")] +public class MapGenerationConfig : ScriptableObject +{ + [Header("길이 영역")] + public int lengthTiles = 120; // 가로 Tile 총 길이 (1 Tile = 1 Unity unit) + + [Header("거점·밀도 영역")] + [Range(0f, 1f)] public float spawnDensity = 0.4f; + public int minSpawnSpacingTiles = 12; + public int maxSpawnPerMap = 16; + + [Header("발판 영역")] + [Range(0f, 1f)] public float platformDensity = 0.5f; + public int minPlatformGapTiles = 3; + public int maxPlatformGapTiles = 6; + public int minPlatformWidthTiles = 2; + public int maxPlatformWidthTiles = 6; + public int minPlatformHeight = 2; // 지면 위 Tile 단위 + public int maxPlatformHeight = 5; // 점프 도달 5.06m 영역 (§2-5) + + [Header("Start/Goal 영역")] + public int startMarginTiles = 4; // 좌측 끝 Start Point margin + public int goalMarginTiles = 4; // 우측 끝 Goal margin + + [Header("리소스 영역")] + public MapResourceCatalog catalog; + public PlatformerJumpProfile jumpProfile; + public StageThemeProfile stageTheme; // 시각 테마 (Tile 가중치) +} +``` + +### 4-2. 출력 (in-memory) + +```csharp +public class MapBlueprint +{ + public int lengthTiles; + public int height; // 청크 영역 최대 높이 + public List terrain; // 지면 Tile (Layer 0) + public List platforms; // 공중 발판 Tile (Layer 16) + public List spawnPoints; // Enemy spawn 거점 + public Vector2 startPoint; // Player 시작 좌표 + public Vector2 goalPoint; // VictoryZone 좌표 + public List backgroundProps; // fence·building 등 배경 Prefab + public List gimmicks; // 함정·이동 발판 등 (§11) + public int generationSeed; // 추적용 (PD 결정 3: 매번 랜덤이나 디버그 추적) +} +``` + +### 4-3. 절차 (의사 코드) + +``` +Generate(config): + 1. seed = Random.Range(int.MinValue, int.MaxValue) + Random.InitState(seed) // PD 결정 3: 매번 완전 랜덤 (사용자 입력 X, 디버그용 기록만) + + 2. lengthTiles = config.lengthTiles + + 3. ── 청크 분할 ── + chunks = SplitIntoChunks(lengthTiles, chunkSize=20) + 각 chunk 영역 Theme 변동 권고 (§4-4) + + 4. ── 지면 생성 (TerrainPlanner) ── + terrain = [] + baseY = 0 + for x in 0..lengthTiles: + // 자연스러운 고저차 — Perlin noise 변조 (±2 tile) + y = baseY + RoundedPerlin(x * 0.1f, amplitude=2) + terrain.Add( {x, y, TileGround} ) + // 표면 1 Tile = TileGroundTop + terrain.Add( {x, y+1, TileGroundTop} ) — y+1 미사용 (충돌 영역 영역) + + 5. ── 공중 발판 생성 (PlatformLayoutPlanner) ── + platforms = [] + x = config.startMarginTiles + 5 + while x < lengthTiles - config.goalMarginTiles: + if Random.value < config.platformDensity: + width = Random.Range(config.minPlatformWidthTiles, config.maxPlatformWidthTiles+1) + height = Random.Range(config.minPlatformHeight, config.maxPlatformHeight+1) + // 점프 도달 가능성 검증 (jumpProfile) + canReach = ValidateJumpReach(prevPlatformOrGround, {x, terrainY+height, width}) + if canReach: + platforms.AddRange(GeneratePlatformTiles(x, terrainY+height, width)) + x += width + Random.Range(config.minPlatformGapTiles, config.maxPlatformGapTiles+1) + continue + x += 1 + + 6. ── 거점 생성 (SpawnPointPlanner) ── + targetCount = floor(lengthTiles * config.spawnDensity / config.minSpawnSpacingTiles) + targetCount = min(targetCount, config.maxSpawnPerMap) + spawnPoints = [] + // 거점 = 지면 + 일부 공중 발판 (PD 결정 안건 §15) + candidates = AllValidSpawnPositions(terrain, platforms, marginFromStart=8, marginFromGoal=8, minSpacing=config.minSpawnSpacingTiles) + Shuffle(candidates) + spawnPoints = candidates.Take(targetCount) + 각 SpawnPoint 영역 EnemyType = RandomFromCatalog(config.catalog.enemyPrefabs) + + 7. ── Start/Goal ── + startPoint = (config.startMarginTiles, terrain[startMarginTiles].y + 1.5) + goalPoint = (lengthTiles - config.goalMarginTiles, terrain[lengthTiles-goalMarginTiles].y + 1.5) + + 8. ── 배경·기믹 ── + backgroundProps = ScatterBackgroundProps(terrain, config.catalog.backgroundPrefabs, density) + gimmicks = ApplyGimmickRules(config.catalog.gimmickPrefabs, terrain, platforms, density) + + 9. return MapBlueprint { ... } +``` + +### 4-4. 청크 분할 권고 (단조 영역 회피) + +- chunkSize = 20 Tile 권고 +- 각 chunk 영역 platformDensity 가중치 변동 (Intro=0.3, Mid=0.6, BossPre=0.4) +- stageTheme.tileVariantWeights에 따라 chunk별 시각 Tile pool 변동 +- PD 결정 안건 §15-3 — chunk 영역 자체 옵션 (스테이지 진행 양상) 노출 영역 + +### 4-5. ValidateJumpReach (§6 정합) + +```csharp +bool ValidateJumpReach(PlatformAnchor from, PlatformAnchor to) +{ + float dx = Mathf.Abs(to.x - from.x); + float dy = to.y - from.y; // 위로 이동 = 양수 + + // 점프 도달 가능 영역: §2-5 실측 + float maxHorizontal = jumpProfile.safeHorizontalDistance; // 5.78m (90% margin) + float maxVertical = jumpProfile.safeVerticalHeight; // 5.06m + + // 수평 거리 cap + if (dx > maxHorizontal) return false; + + // 위로 점프: 높이 cap + if (dy > maxVertical) return false; + + // 발판 → 발판: 포물선 통과 가능성 (단순 보수 — 최대 높이까지 도달 가능 시 OK) + // dy 음수(아래) 발판 = 항상 도달 가능 + return true; +} +``` + +--- + +## §5. Tile (배경) vs Prefab (기믹) 분리 룰 + +PD 결정 2 — **양쪽 다** 활용. + +### 5-1. Tile 영역 (Tilemap) + +| 영역 | Tile 자산 | Layer | 사용 | +|------|---------|-------|------| +| 지면 (Level Tilemap) | TileGround·TileGroundTop·TileGroundDark | 0 | 무한 지면·고저차 | +| 공중 발판 (AutoForeground Tilemap) | TileFloatingLeftEdge·TileFloatingTileMiddle·TileFloatingRightEdge·cloud | 16 | Drop-Through 발판 | +| 배경 장식 (BackgroundTilemap) | fence·MidgroundFiller (선택) | (선택·collider X 또는 별도 Layer) | 시각 | + +### 5-2. Prefab 영역 (Instantiate) + +| 영역 | Prefab | 사용 | +|------|--------|------| +| Player | Player.prefab | Start Point 1 인스턴스 | +| Enemy | Enemy.prefab 또는 Enemy_M00N_*.prefab | SpawnPoint 영역 인스턴스 | +| 배경 건물 | ShortBuilding·TallBuilding | 배경 배치 (Prefab 또는 Tile both 옵션) | +| 기믹 | (신규) MovingPlatform·Trap·CheckPoint·VictoryZone 등 | 옵션 등록 영역 (§11) | + +### 5-3. 결정 룰 + +``` +요소 = 동적 동작·복잡 컴포넌트 영역? → Prefab +요소 = 정적 시각·단순 충돌·반복 배치? → Tile +경계 영역(건물 등) → 옵션·MapResourceCatalog에서 PD 자유 선택 +``` + +--- + +## §6. 발판 배치 룰 (자연스러운 레벨 디자인) + +### 6-1. PlatformerJumpProfile (실측 SOT) + +```csharp +[CreateAssetMenu(menuName = "EerieVillage/Map/Jump Profile")] +public class PlatformerJumpProfile : ScriptableObject +{ + [Header("실측 (KinematicObject·PlayerController·PlatformerModel)")] + public float jumpTakeOffSpeed = 7f; + public float jumpModifier = 1.5f; + public float gravity = 9.81f; + public float maxSpeed = 3f; + public float gravityModifier = 1f; + + // 산출 (자동 계산 — OnValidate) + public float v0 => jumpTakeOffSpeed * jumpModifier; + public float effectiveGravity => gravity * gravityModifier; + public float maxVerticalHeight => (v0 * v0) / (2f * effectiveGravity); // 5.62m + public float jumpRoundTripTime => 2f * v0 / effectiveGravity; // 2.14s + public float maxHorizontalDistance => maxSpeed * jumpRoundTripTime; // 6.42m + + [Header("안전 margin (자연 레벨 디자인)")] + [Range(0.5f, 1.0f)] public float safetyMargin = 0.9f; + public float safeVerticalHeight => maxVerticalHeight * safetyMargin; // 5.06m + public float safeHorizontalDistance => maxHorizontalDistance * safetyMargin; // 5.78m +} +``` + +### 6-2. 배치 룰 (자연스러움) + +| 룰 | 수치 | 근거 | +|----|-----|------| +| 발판 간 수평 간격 min | 3 Tile (3m) | 1 Tile 점프 가능·연속 점프 리듬 | +| 발판 간 수평 간격 max | 6 Tile (6m) | safeHorizontalDistance 5.78m 영역 안 | +| 발판 높이 min | 2 Tile (지면 위 2m) | Player 캡슐 높이 약 1m → 점프 의무 영역 | +| 발판 높이 max | 5 Tile (지면 위 5m) | safeVerticalHeight 5.06m 영역 안 | +| 발판 폭 min | 2 Tile (2m) | EnemyController cliffCheckDistance=1m 영역 안전 patrol | +| 발판 폭 max | 6 Tile (6m) | 단조 영역 회피 | +| 연속 점프 (계단식) 영역 dx | 3~4 Tile, dy +1~+2 Tile | 자연 상승 리듬 | +| 사선·이중 점프 | **PD 결정 안건 §15-2** | 현 KinematicObject 영역 2단 점프 미구현 | + +### 6-3. 검증 영역 + +`MapGenerator.PlatformLayoutPlanner`가 모든 발판 영역 `PlatformerJumpProfile.ValidateJumpReach()` 통과 검증. 미통과 시 해당 발판 폐기 후 위치·높이 재시도 (최대 5회 retry). + +### 6-4. EnemyController patrol 영역 (§9 정합) + +발판 폭 ≥ 2 Tile + EnemyController fallThreshold=1m·cliffCheckDistance=1m → spawn 발판 영역 자동 patrol 동작 보장. + +--- + +## §7. 바닥 자동 충돌 적용 + +### 7-1. PD 요구 "바닥의 길은 사용자가 일일이 수정하지 않아도 충돌 영역이 자연스럽게 적용" + +### 7-2. 기존 자산 활용 (§2-8 실측) + +- 모든 Tile 자산 m_ColliderType=1 (Sprite) 이미 강제 +- 본 설계 = Tilemap 영역 SetTile 시 자동 영역 collider 적용 + +### 7-3. Tilemap 자동 충돌 영역 표준 패턴 + +```csharp +// MapApplier.cs +void ApplyTerrainToLevelTilemap(MapBlueprint blueprint) +{ + Tilemap levelTilemap = FindOrCreateLevelTilemap(); + foreach (var place in blueprint.terrain) + { + levelTilemap.SetTile(new Vector3Int(place.x, place.y, 0), place.tile); + levelTilemap.SetColliderType(new Vector3Int(place.x, place.y, 0), + Tile.ColliderType.Sprite); + } + var tc = levelTilemap.GetComponent(); + if (tc == null) tc = levelTilemap.gameObject.AddComponent(); + tc.compositeOperation = Collider2D.CompositeOperation.Merge; + + // CompositeCollider2D 통합 (지면 영역 단일 collider — 성능·정합) + var cc = levelTilemap.GetComponent(); + if (cc == null) cc = levelTilemap.gameObject.AddComponent(); + var rb = levelTilemap.GetComponent(); + if (rb == null) rb = levelTilemap.gameObject.AddComponent(); + rb.bodyType = RigidbodyType2D.Static; + + tc.ProcessTilemapChanges(); + levelTilemap.gameObject.name = "Level"; // §2-7 GameOptimizer 영역 보존 + levelTilemap.gameObject.layer = 0; // §2-7 GameOptimizer 영역 보존 +} +``` + +### 7-4. 공중 발판 Tilemap 영역 (Drop-Through 영역) + +```csharp +void ApplyPlatformsToAutoForegroundTilemap(MapBlueprint blueprint) +{ + Tilemap fgTilemap = FindOrCreateAutoForegroundTilemap(); + foreach (var place in blueprint.platforms) + { + fgTilemap.SetTile(new Vector3Int(place.x, place.y, 0), place.tile); + fgTilemap.SetColliderType(new Vector3Int(place.x, place.y, 0), + Tile.ColliderType.Sprite); + } + // GameOptimizer 영역 자동 영역 Layer 16 + TilemapCollider 보장 + fgTilemap.gameObject.name = "AutoForeground"; + fgTilemap.gameObject.layer = 16; + EnsureCollider(fgTilemap); +} +``` + +### 7-5. 두 옵션 (PD 결정 안건 §15-4) + +**옵션 A (권고)**: 본 설계 MapApplier 영역 직접 Level/AutoForeground 분리 적용 → GameOptimizer 영역 자동 분류 의존 X (예측성·결정성↑) + +**옵션 B**: 모두 Level Tilemap에 배치 → GameOptimizer.SetupJumpThroughPlatforms() 영역 자동 분류 위임 (기존 시스템 활용·중복 회피) + +→ **§15-4 PD 결정**. + +본 PM 권고 옵션 A — Drop-Through 패턴 28회 시도(BT22~BT47)의 교훈 영역 명시적 분리가 안정. + +### 7-6. Composite·자연스러운 충돌 + +CompositeCollider2D + Merge → 인접 Tile 영역 단일 collider 영역 통합. 가장자리 jitter·작은 틈 영역 차단. + +--- + +## §8. 거점(생성 포인트) + Start Point 배치 + +### 8-1. 옵션 정합 (PD 결정 4) + +```csharp +[Range(0f, 1f)] public float spawnDensity = 0.4f; +// 0.0 = 거점 0개 / 0.5 = 중간 밀도 / 1.0 = 최대 밀도 (maxSpawnPerMap cap) +public int minSpawnSpacingTiles = 12; +public int maxSpawnPerMap = 16; +``` + +### 8-2. 산출 공식 + +``` +desiredCount = floor(lengthTiles * spawnDensity / minSpawnSpacingTiles) +finalCount = min(desiredCount, maxSpawnPerMap) +``` + +예: lengthTiles=120·spawnDensity=0.5·minSpawnSpacingTiles=12 → desiredCount=5·finalCount=5 + +### 8-3. 거점 후보 영역 + +| 영역 | 적격 | +|------|------| +| 지면 평탄 영역 (Tile 폭 ≥3 연속) | ✓ | +| 공중 발판 (폭 ≥3 Tile) | ✓ (PD 결정 안건 §15-5: 거점을 공중 발판에도 둘지) | +| Start Point ±8 Tile | ✗ (난이도 초기) | +| Goal ±8 Tile | ✗ | +| 다른 거점 < minSpawnSpacingTiles | ✗ | + +### 8-4. Start Point + +- 좌측 끝 + `startMarginTiles` (default 4) 위치 +- 지면 Tile 표면 + 1.5m 위 (Player 캡슐 영역 안전 spawn) +- 본 설계 = 항상 좌측 고정 (PD 결정 안건 §15-6 — 양 끝 random 옵션) + +### 8-5. Goal + +- 우측 끝 - `goalMarginTiles` 위치 +- VictoryZone Prefab Instantiate (현 영역 VictoryZone Prefab 영역 검증 필요 — `Mechanics/VictoryZone.cs` 존재 확인됨, §2-7 GameOptimizer 영역 excluded) + +### 8-6. SpawnPoint 영역 (MonoBehaviour 확장) + +```csharp +public class SpawnPoint : MonoBehaviour // 기존 11줄 영역 확장 +{ + [Header("Spawn 영역")] + public GameObject enemyPrefab; // Enemy_M00N or Enemy.prefab + MonsterRandomizer + public float spawnRadiusX = 0.5f; // 거점 ±X Tile 영역 random spawn + public int initialSpawnCount = 1; // 최초 spawn 수 + public int maxConcurrent = 1; // 동시 spawn 상한 (현 영역 1 — re-spawn 영역 PD 결정 §15-7) + + [Header("미리보기 영역 — Editor only")] + public Color gizmoColor = new Color(1f, 0.3f, 0.3f, 0.5f); + + void Start() + { + for (int i = 0; i < initialSpawnCount; i++) + { + Vector3 pos = transform.position + new Vector3( + Random.Range(-spawnRadiusX, spawnRadiusX), 0f, 0f); + var enemy = Instantiate(enemyPrefab, pos, Quaternion.identity); + // EnemyController.Awake → _startX·_startY 설정 자동 진행 (§2-6 정합) + } + } + +#if UNITY_EDITOR + void OnDrawGizmos() + { + Gizmos.color = gizmoColor; + Gizmos.DrawWireSphere(transform.position, 0.5f); + Gizmos.DrawLine(transform.position + Vector3.left * spawnRadiusX, + transform.position + Vector3.right * spawnRadiusX); + } +#endif +} +``` + +--- + +## §9. 몬스터 spawn 룰 + +### 9-1. PD 요구 "현재 만들어진 몬스터 이동 패턴을 활용" + +§2-6 EnemyController 자동 patrol 시스템 = **완전 계승**. SpawnPoint 영역 Instantiate만 처리. + +### 9-2. Enemy spawn 절차 + +``` +1. MapApplier가 SpawnPoint Prefab 영역 Scene에 배치 (위치=거점 좌표) +2. SpawnPoint.Start() → enemyPrefab Instantiate (Awake → MonsterRandomizer 영역 controller random) +3. EnemyController.Awake() → _startX = transform.position.x, _startY = transform.position.y +4. EnemyController.Start() → MeasureSafeWalkDistance(±1) — Tilemap cell 기반 좌우 patrol 거리 측정 +5. _isInitialized = true → UpdatePatrol() 영역 자동 patrol 시작 +6. 떨어짐 검출 (y < _startY - 1.0) → 시작 위치 텔레포트 +``` + +### 9-3. EnemyType 카탈로그 (MapResourceCatalog 영역) + +| Catalog 슬롯 | 영역 | +|------------|------| +| `enemyPrefabs[]` | Enemy_M001_Wolf·M002_Bat·M003_ZombieM·M004_ZombieF·M005_Ghost·M006_Spider | +| `enemyWeights[]` | stageTheme별 가중치 (Stage1=Wolf 70%·Bat 30% 등) | +| `flyingEnemyPrefabs[]` | M002 Bat (cliffCheck skip·공중 spawn) | + +### 9-4. spawn 위치 영역 — 거점 주변 + +``` +spawnPos = spawnPoint.position + Vector3(Random(-spawnRadiusX, spawnRadiusX), 0, 0) +``` + +EnemyController _startX는 Awake 시점 transform.position.x → 본 spawn 위치 = patrol 기준점. + +### 9-5. 동시 spawn 상한 + +현 영역 SpawnPoint 1개당 1 Enemy. **재-spawn (사망 후 시간 경과 재출현) 영역 = PD 결정 안건 §15-7**. + +### 9-6. 공중 SpawnPoint (M002 Bat) + +`IsFlying=true` 영역 EnemyController는 `flyingYOffset = 2f` 자동 적용 → SpawnPoint 영역 지면 위 SpawnPoint에 M002 prefab 배치해도 Awake 영역 +2m 자동 상승. 별도 영역 처리 불요. + +--- + +## §10. 시각 시뮬레이터 — Unity Editor Window 1순위 결정 + +### 10-1. 가능성 판단 (PD 결정 1 — 1순위 EditorWindow) + +**판단 결과: 가능. 1순위 EditorWindow 채택.** + +근거: +- `E:/EerieVillage/Assets/Editor/` 영역 GitAutoSync만 존재·신규 EditorWindow 도입 깨끗 (§2-13) +- Unity EditorWindow + GUILayout + Handles.Draw* 영역 표준 패턴 +- Tile data·SpawnPoint 위치·점프 도달 영역 모두 in-memory MapBlueprint 영역 직접 그리기 가능 (Scene 적용 전) + +### 10-2. MapPreviewWindow 구조 (Editor 폴더) + +```csharp +// E:/EerieVillage/Assets/Editor/Map/MapPreviewWindow.cs (신규) +public class MapPreviewWindow : EditorWindow +{ + [MenuItem("EerieVillage/Map/Preview")] + public static void Open() => GetWindow("Map Preview"); + + MapGenerationConfig config; + MapBlueprint currentBlueprint; + Vector2 previewScroll; + float zoom = 1f; + + void OnGUI() + { + EditorGUILayout.LabelField("Map Preview", EditorStyles.boldLabel); + config = (MapGenerationConfig)EditorGUILayout.ObjectField("Config", config, + typeof(MapGenerationConfig), false); + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Generate", GUILayout.Width(100))) + { + currentBlueprint = MapGenerator.Generate(config); + } + if (GUILayout.Button("Apply to Scene", GUILayout.Width(120))) + { + MapApplier.Apply(currentBlueprint, config); + } + if (GUILayout.Button("Clear Scene", GUILayout.Width(100))) + { + MapApplier.Clear(); + } + EditorGUILayout.EndHorizontal(); + + zoom = EditorGUILayout.Slider("Zoom", zoom, 0.2f, 3f); + + if (currentBlueprint != null) + { + DrawPreview(currentBlueprint); + } + } + + void DrawPreview(MapBlueprint bp) + { + // GUI.DrawTexture로 grid 배경 + // bp.terrain·bp.platforms·bp.spawnPoints·bp.startPoint·bp.goalPoint를 + // Rect로 변환·GUI.Box 영역 그림 + // 점프 도달 영역 = Handles.DrawSolidArc 또는 GUI line + var rect = GUILayoutUtility.GetRect(position.width, position.height - 100); + previewScroll = GUI.BeginScrollView(rect, previewScroll, + new Rect(0, 0, bp.lengthTiles * 16 * zoom, + bp.height * 16 * zoom)); + // Terrain (회색) + foreach (var t in bp.terrain) + EditorGUI.DrawRect(TileToRect(t.x, t.y, zoom), new Color(0.4f, 0.3f, 0.2f)); + // Platforms (녹색) + foreach (var p in bp.platforms) + EditorGUI.DrawRect(TileToRect(p.x, p.y, zoom), new Color(0.3f, 0.7f, 0.3f)); + // SpawnPoints (빨강) + foreach (var s in bp.spawnPoints) + EditorGUI.DrawRect(WorldToRect(s.position, zoom, size: 0.6f), + new Color(0.9f, 0.2f, 0.2f)); + // Start (파랑) + EditorGUI.DrawRect(WorldToRect(bp.startPoint, zoom, size: 1f), + new Color(0.2f, 0.5f, 0.9f)); + // Goal (노랑) + EditorGUI.DrawRect(WorldToRect(bp.goalPoint, zoom, size: 1f), + new Color(0.9f, 0.9f, 0.2f)); + // 점프 도달 영역 (반투명 영역) — option toggle + if (showJumpReach) + DrawJumpReachOverlays(bp); + GUI.EndScrollView(); + } +} +``` + +### 10-3. 시각 요소 + +| 요소 | 색상 | 표시 | +|------|------|------| +| 지면 Tile | 갈색 0.4·0.3·0.2 | 1×1 Rect | +| 공중 발판 Tile | 녹색 0.3·0.7·0.3 | 1×1 Rect | +| SpawnPoint | 빨강 0.9·0.2·0.2 | 0.6×0.6 Rect + 거점 ±spawnRadiusX 선 | +| Start Point | 파랑 0.2·0.5·0.9 | 1×1 Rect + "S" 텍스트 | +| Goal Point | 노랑 0.9·0.9·0.2 | 1×1 Rect + "G" 텍스트 | +| 점프 도달 영역 | 반투명 청 (toggle) | 발판 가장자리 영역 ±5.78m·+5.06m 호 | + +### 10-4. Fallback — Scene 미리보기 (옵션 어렵 시) + +본 PM 판단 = EditorWindow 영역 가능 — Fallback 비활성. +만약 GUILayout 영역 성능 한계 발생 시 → Scene Hierarchy 영역 Empty GameObject ("MapPreview_Temp") 영역 placeholder Sprite Instantiate → SceneView 영역 직접 표시. + +### 10-5. Editor 호출 영역 워크플로우 + +``` +1. PD: MapGenerationConfig SO Editor 영역 옵션 조정 +2. PD: EerieVillage/Map/Preview 메뉴 → MapPreviewWindow 활성 +3. PD: [Generate] → in-memory MapBlueprint 확인 +4. PD: 시각 영역 만족 시 [Apply to Scene] → Tilemap·Prefab 적용 +5. PD: 불만족 시 [Generate] 반복 (매번 완전 랜덤·PD 결정 3) +6. PD: Play → 실제 게임 확인 +``` + +--- + +## §11. 맵 리소스 등록 시스템 + +### 11-1. MapResourceCatalog (ScriptableObject) + +```csharp +[CreateAssetMenu(menuName = "EerieVillage/Map/Resource Catalog")] +public class MapResourceCatalog : ScriptableObject +{ + [Header("지면 Tile 영역")] + public TileEntry[] groundTiles; // TileGround·TileGroundTop·TileGroundDark + + [Header("공중 발판 Tile 영역")] + public TileEntry[] platformLeftEdge; + public TileEntry[] platformMiddle; + public TileEntry[] platformRightEdge; + public TileEntry[] platformCloud; // 변형 (cloud.asset) + + [Header("배경 Tile 영역 (선택)")] + public TileEntry[] backgroundTiles; // fence·MidgroundFiller + + [Header("Enemy Prefab 영역")] + public PrefabEntry[] enemyPrefabs; // Enemy_M001~M006 + + [Header("Player Prefab 영역")] + public GameObject playerPrefab; + + [Header("Goal Prefab 영역")] + public GameObject goalPrefab; // VictoryZone + + [Header("배경 Prefab 영역")] + public PrefabEntry[] backgroundPrefabs; // ShortBuilding·TallBuilding 등 + + [Header("기믹 Prefab 영역 (신규·향후 확장)")] + public PrefabEntry[] gimmickPrefabs; // 이동 발판·낙하 함정·체크포인트 등 + + [Header("SpawnPoint Prefab 영역")] + public GameObject spawnPointPrefab; // SpawnPoint.cs 부착 영역 +} + +[System.Serializable] +public class TileEntry +{ + public TileBase tile; + [Range(0f, 10f)] public float weight = 1f; + public string[] tags; // "stage1", "dark" 등 +} + +[System.Serializable] +public class PrefabEntry +{ + public GameObject prefab; + [Range(0f, 10f)] public float weight = 1f; + public string[] tags; +} +``` + +### 11-2. PD 자유 등록 영역 + +PD가 신규 Tile·Prefab 영역 영역 추가 시 → MapResourceCatalog asset 영역 Inspector 영역 슬롯 영역 드래그·드롭. 코드 수정 X·tag·weight 영역 분류만. + +### 11-3. StageThemeProfile (스테이지별 Theme) + +```csharp +[CreateAssetMenu(menuName = "EerieVillage/Map/Stage Theme")] +public class StageThemeProfile : ScriptableObject +{ + public string stageName = "Stage1_DuskVillageOutskirts"; + public MapResourceCatalog catalog; // base catalog + public string[] filterTags; // "stage1" tag 영역 Tile만 활용 + public Color skyTint = Color.white; + // 추후 — 음악·환경 영역 +} +``` + +### 11-4. 기획 SOT 5종 스테이지 정합 + +`프로젝트/EerieVillage/기획/level/01_스테이지_구조.md` §2 영역 5종 stageTheme 영역 매핑: + +| Stage | StageThemeProfile.stageName | filterTags | +|-------|---------------------------|------------| +| 1 황혼 고을 어귀 | Stage1_DuskVillageOutskirts | stage1·dusk | +| 2 버려진 산사 | Stage2_AbandonedMountainTemple | stage2·moonlit | +| 3 뼈 바위 계곡 | Stage3_BoneRockValley | stage3·foggy | +| 4 폐가·지하 창고 | Stage4_AbandonedHouseBasement | stage4·midnight | +| 5 공동묘지 심부 | Stage5_GraveyardDepths | stage5·dawn | + +--- + +## §12. 기존 시스템 통합 영역 + +### 12-1. BT5-Dev 발판 시스템 영역 + +| 시스템 | 본 설계 활용 | +|--------|------------| +| KinematicObject contactFilter | Drop-Through Layer 16 발판 — 본 설계 AutoForeground Tilemap Layer 16 강제 정합 | +| PlayerController UpdateContactFilterForDropThrough | 본 설계 무관 (Player 영역 그대로) | +| GameOptimizer.SetupJumpThroughPlatforms | **상호작용 의무** — §7-5 옵션 A/B 결정 | +| Tile m_ColliderType=1 (Sprite) | §2-8 모든 Tile 기 강제 → 본 설계 SetColliderType(Sprite) 영역 정합 | +| CompositeCollider2D Merge | 본 설계 Level Tilemap 영역 부착 (§7-3) | + +### 12-2. EnemyController patrol 영역 + +| 영역 | 본 설계 정합 | +|------|------------| +| _startX·_startY Awake 측정 | SpawnPoint.Instantiate → Enemy.Awake 자동 동작 | +| MeasureSafeWalkDistance Tilemap cell 기반 | 본 설계 = AutoForeground Tilemap 영역 등록 시 자동 patrol | +| cliffCheckDistance=1m | 본 설계 발판 폭 min 2 Tile 영역 안전 | +| fallThreshold=1m → 시작 위치 텔레포트 | 본 설계 spawn 발판 영역 EnemyController 자동 복귀 | +| IsFlying M002 Bat | 본 설계 catalog 영역 flyingEnemyPrefabs 영역 별도 분류 | + +### 12-3. KinematicObject 점프 물리 영역 + +본 설계 = `PlatformerJumpProfile` SO 영역 실측 수치 직접 참조. KinematicObject 영역 변경 X. + +### 12-4. M001~M006 6 Enemy prefab 영역 + +본 설계 = MapResourceCatalog 영역 6 prefab 등록·stageTheme별 가중치. MonsterRandomizer 영역 random 6종 활용 영역 = 옵션 (Enemy.prefab + MonsterRandomizer) vs (Enemy_M00N 직접 prefab) — **PD 결정 안건 §15-8**. + +### 12-5. BT12 스킬 시스템 영역 + +**영향 없음** (§2-11). Player·Enemy 영역 그대로 spawn → PlayerSkillInventory·ActiveSkillRuntime·6 Effector 모두 정상 동작. + +### 12-6. GitAutoSync (Editor) + +EerieVillage `E:/EerieVillage/Assets/Editor/GitAutoSync/` 영역 영향 X (별도 영역). + +--- + +## §13. Phase 2 작업 단위 분해 (C49 단계 정합) + +### 13-1. Phase 2-A — 데이터 SOT 영역 (클라이언트팀 Sonnet) + +| 산출물 | 위치 | 분량 | +|--------|------|------| +| PlatformerJumpProfile.cs (ScriptableObject) | `Assets/Scripts/Map/Data/` | 50줄 | +| MapResourceCatalog.cs + TileEntry/PrefabEntry | `Assets/Scripts/Map/Data/` | 80줄 | +| StageThemeProfile.cs | `Assets/Scripts/Map/Data/` | 30줄 | +| MapGenerationConfig.cs | `Assets/Scripts/Map/Data/` | 60줄 | +| MapBlueprint.cs + Place 영역 4종 struct | `Assets/Scripts/Map/Data/` | 100줄 | +| Default .asset 인스턴스 4종 (실측 수치 반영) | `Assets/Data/Map/` | (PD 미리 1개·확장 PD) | + +### 13-2. Phase 2-B — 절차 생성기 (클라이언트팀 Sonnet) + +| 산출물 | 분량 | +|--------|------| +| MapGenerator.cs (static·Generate 메서드) | 150줄 | +| TerrainPlanner.cs (Perlin 변조·고저차) | 80줄 | +| PlatformLayoutPlanner.cs (배치 룰·ValidateJumpReach) | 150줄 | +| SpawnPointPlanner.cs (밀도·간격·후보 영역) | 100줄 | +| BackgroundPropPlanner.cs (배경 산포) | 50줄 | +| EditMode 테스트 — 100회 Generate·ValidateJumpReach 모든 발판 통과 검증 | 200줄 | + +### 13-3. Phase 2-C — Editor Window + Applier (클라이언트팀 Sonnet) + +| 산출물 | 분량 | +|--------|------| +| MapPreviewWindow.cs (EditorWindow + DrawPreview) | 250줄 | +| MapApplier.cs (Tilemap.SetTile + Instantiate + Clear) | 150줄 | +| SpawnPoint.cs 확장 (Spawn 영역 옵션·OnDrawGizmos) | 80줄 | +| Editor 메뉴·shortcut | (포함) | + +### 13-4. Phase 2-D — QA·정합 (개발팀장 Opus 검증) + +| 영역 | 영역 | +|------|------| +| Stage1~5 Default Config 각 영역 Generate + Apply + Play 검증 | 5종 | +| 점프 도달 가능성 검증 — 100% pass | 정량 | +| Enemy patrol 정합 검증 (BT109 Tilemap cell 영역 정합) | 정량 | +| GameOptimizer SetupJumpThroughPlatforms 충돌 검증 | 정성 | +| 시뮬레이터 Apply→Play 일관성 검증 | 정성 | + +### 13-5. C49 표준 프로세스 적용 + +1. **개발팀장 (Opus·본 문서)** 설계 v1 산출 ✓ +2. **클라이언트팀장 (Opus)** 본 문서 영역 Phase 2-A/B/C 분할 위임 결정 +3. **게임플레이 프로그래머 (Sonnet)** 코드 구현 +4. **클라이언트팀장 (Opus)** Phase 2 코드 검증 +5. **개발팀장 (Opus)** Phase 2-D 영역 정합 검증 → 완료 아카이브 + +--- + +## §14. 기각안 + +### 14-1. (기각 1) Seed 입력 기반 재현 가능 랜덤 채택 + +**기각 이유**: PD 결정 3 — "매번 완전 랜덤 (Seed 입력 X · 재현성 비요구)". Seed 입력 UI·재현 로직 영역 코드 부담 + PD 명시 비요구. + +**보완**: MapBlueprint.generationSeed 영역 자동 기록 (디버그·로그 영역 추적용). PD가 후속 재현 의무 발생 시 generationSeed 영역 InitState 재 invoke 가능. + +### 14-2. (기각 2) 전체 수동 배치 + 부분 셔플 (기존 기획 §5 채택) + +**기각 이유**: PD 신규 지시 (2026-05-18) = "맵의 길이만 지정하면, 랜덤으로 자동 생성" → 기획 §5 "전체 수동 배치 + 구간 2 적 배치 소규모 셔플" **OVERRIDE**. + +**기획 후속 정합 안건**: §15-1 PD 결정 대기. 기획팀 영역 SOT 정정 의무 (level-designer 후속). + +### 14-3. (기각 3) Cellular Automata 또는 BSP 영역 던전 생성 알고리즘 + +**기각 이유**: 횡스크롤 플랫포머 영역 1D 진행 영역 단순 chunk 분할 (4-3) 영역 충분. CA·BSP 영역 2D top-down 영역 적합. + +### 14-4. (기각 4) Runtime Generate (게임 진입 시 매번 절차 생성) + +**기각 이유**: 본 설계 Phase 1 = Editor 영역 Generate→Apply→Save Scene. Runtime Generate 옵션은 향후 확장 (Phase 3-C 영역). 현 Phase = PD 시각 검토 영역 = Editor 영역 적용 후 Play. + +**보완**: MapGenerator·MapApplier 영역 Editor·Runtime 양립 가능 영역 설계 → Phase 3-C 영역 즉시 활성 가능. + +### 14-5. (기각 5) Procedural 영역 별도 신규 Scene 생성 + +**기각 이유**: 기존 `Ingame.unity` 영역 단일 Scene 영역 활용 — Player·UI·Camera·Health·Skill 영역 모두 부착됨. 본 설계 = Ingame.unity 영역 Tilemap·SpawnPoint만 절차 영역 교체. + +### 14-6. (기각 6) Boss 방 영역 절차 생성 포함 + +**기각 이유**: 기획 §3-2 영역 보스 방 = "고정 카메라·후방 차단·전용 지형". 자연 생성 영역 적합 X. 본 설계 = 도입·전개 영역만, 보스 방 = 별도 수동 Scene 또는 본 설계 영역 마지막 chunk 영역 hand-place placeholder. + +**보완**: MapGenerationConfig 영역 `bool includeBossRoom` 영역 옵션 + Boss 방 영역 별도 prefab 영역 Instantiate (현 Phase 1 영역 PD 결정 보류·§15-9 영역). + +--- + +## §15. PD 결정 대기 안건 (Phase 2 진입 전 결정 의무) + +### 15-1. 기획 SOT 정합 — `프로젝트/EerieVillage/기획/level/01_스테이지_구조.md` §5 OVERRIDE 처리 + +기획 영역 §5 "전체 수동 배치 + 구간 2 적 배치 소규모 셔플" vs PD 신규 지시 "맵의 길이만 지정하면 랜덤으로 자동 생성" 충돌. + +**옵션 A**: 기획 SOT 정정 — level-designer 후속 갱신 +**옵션 B**: 두 영역 공존 — 본 설계 절차 생성기 + 기획 수동 배치 영역 두 가지 운용 + +### 15-2. 사선·이중 점프 도입 여부 + +현 KinematicObject 영역 2단 점프 X. 본 설계 §6-2 영역 단일 점프 영역만 ValidateJumpReach. + +**옵션 A**: 단일 점프만 유지 — 본 설계 그대로 +**옵션 B**: 2단 점프 추가 — 본 설계 maxVerticalHeight 약 2배 영역 재산출 의무 (PlayerController.UpdateJumpState 영역 추가 구현) + +### 15-3. chunk 영역 옵션 노출 영역 + +본 설계 §4-4 영역 chunk 영역 platformDensity 가중치 변동 (Intro 0.3·Mid 0.6·BossPre 0.4) 기본값. + +**옵션 A**: 기본값 고정 — PD 옵션 노출 X +**옵션 B**: MapGenerationConfig 영역 `ChunkProfile[]` 영역 PD 노출 — 세부 영역 영역 + +### 15-4. Level/AutoForeground 분리 전략 + +§7-5 영역 옵션 A (본 설계 영역 직접 분리·권고) vs 옵션 B (GameOptimizer 위임). + +### 15-5. 공중 발판 영역 SpawnPoint 배치 여부 + +§8-3 영역 공중 발판 (폭 ≥3 Tile) 영역 거점 후보 영역. + +**옵션 A**: 지면만 거점 — 안전·patrol 거리 보장 +**옵션 B**: 공중 발판 영역 거점 — 입체적 전투·플랫포밍 강조 (단·spawn Enemy 떨어짐 위험) + +### 15-6. Start Point 좌측 고정 vs random + +§8-4 영역 본 설계 영역 항상 좌측 고정. 향후 영역 양 끝 random·역방향 진행 영역. + +### 15-7. Enemy 재-spawn (사망 후 시간 경과 재출현) + +§9-5 영역 SpawnPoint 1개당 1 Enemy 영역 1회 spawn 영역. 재-spawn 영역 옵션·timer·count 영역. + +### 15-8. Enemy spawn 방식 — `Enemy.prefab + MonsterRandomizer` vs `Enemy_M00N` 직접 + +§12-4 영역 두 영역 영역. 본 PM 권고 = 후자 (catalog 영역 명시적 prefab 영역 가중치). + +### 15-9. Boss 방 포함 여부 (현 Phase 1) + +§14-6 영역 보스 방 영역 별도 영역 영역 → 본 Phase 1 영역 영역 X. 추후 영역. + +### 15-10. 맵 길이 단위 — Tile vs 미터 vs 청크 + +본 설계 영역 Tile 단위 영역 (`lengthTiles`). 1 Tile = 1 Unity unit 가정. + +**옵션 A**: Tile 단위 유지 (개발 영역 정합) +**옵션 B**: 미터·청크 단위 영역 PD 친화 영역 변환 UI 추가 + +### 15-11. 옵션 노출 영역 — MapGenerationConfig 영역 PD 자유도 + +본 설계 §4-1 영역 옵션 12종. PD 영역 너무 많은 옵션 영역 = 결정 부담 영역. + +**옵션 A**: 12종 모두 노출 (PD 자유도 최대) +**옵션 B**: 5~6종만 노출 (lengthTiles·spawnDensity·platformDensity·stageTheme·includeBossRoom 등) — Advanced 영역 toggle + +--- + +## §16. C50 Phase 2 토큰 옵션 사전 보고 + +### 16-1. Phase 2 분량 추정 + +| 단계 | 코드 라인 추정 | 토큰 추정 | +|------|--------------|---------| +| Phase 2-A 데이터 SOT (5종 SO + 인스턴스) | 320 라인 | ~12K | +| Phase 2-B 절차 생성기 (5종 Planner + 테스트) | 530 라인 | ~25K | +| Phase 2-C Editor Window + Applier (3종) | 480 라인 | ~22K | +| Phase 2-D 정합 검증 + 5 stage Config | 100 라인 + 검증 | ~10K | +| **합계** | **1430 라인** | **~69K** | + +### 16-2. 옵션 사전 보고 (C50) + +**옵션 (a) 단일 Phase 2 일괄 처리**: +- 단일 세션 영역 ~70K 토큰 +- 위험: 컨텍스트 영역 한계 영역 일부 정합 영역 영역 +- 권고도: 중 + +**옵션 (b) Phase 2-A/B/C/D 분할 순차 진행** (P32 정합·본 PM 권고): +- 2-A 단독 ~12K → 검증 → 2-B 단독 ~25K → 검증 → 2-C 단독 ~22K → 검증 → 2-D +- 각 단계 영역 클라이언트팀장 Opus 위임·게임플레이 프로그래머 Sonnet 작업·클라이언트팀장 Opus 검증 +- 권고도: **상** — Drop-Through 발판 영역 BT22~BT47 28회 시도 영역 교훈 + +### 16-3. 본 PM 권고 + +**옵션 (b) Phase 2-A/B/C/D 분할 순차 진행** 영역 PD 승인 의무. + +각 Phase 영역 클라이언트팀장 (`client-team-lead`) Opus 영역 위임. 단순 반복 영역 = 게임플레이 프로그래머 Sonnet 영역 직접 위임 가능 (Phase 2-A 데이터 SO 영역 등). + +--- + +## §17. 변경 이력 + +| 일시 | 변경 | 사유 | 기안 | +|------|------|-----|------| +| 2026-05-18 | v1.0 초안 — Phase 1 설계 완료 | PD 직접 지시 BT13-Dev-Map (2026-05-18) | 개발팀장 (dev-team-lead) | + +--- + +## §18. 종결 + +본 Phase 1 설계 완료. Phase 2 진입 전 §15 PD 결정 대기 안건 11건 영역 결정 의무. 결정 후 클라이언트팀장 영역 Phase 2-A 위임 진입. + +**관련 SOT 영역**: +- 본 문서 = 맵 시스템 설계 SOT (단일) +- 스킬 시스템 영역 영향 X (BT12 정합) +- BT5-Dev 발판 시스템 영역 완전 계승 (GameOptimizer·KinematicObject·EnemyController) +- 기획 §5 자동 생성 vs 수동 배치 영역 PD OVERRIDE 후속 정합 의무 (§15-1) + +--- + +**작성**: 개발팀장 (`dev-team-lead`) +**근거**: PD 직접 지시 BT13-Dev-Map (2026-05-18) + PD 추가 결정 4건 (시각 시뮬레이터·리소스 단위·랜덤성·거점 밀도) +**관련 규칙**: C39-10 사전 실측 의무·C49 표준 프로세스·C50 토큰 사전 승인·P18 설계 문서화·P32 맥락 분할 순차 진행