# 전투 연출 (P3) — 설계 - 날짜: 2026-06-11 - 대상: `tools/deck/gen-slaydeck.mjs`(카드 드래그·연출·적 턴 시퀀스), 생성물 - 상태: 승인됨(사용자 사전 위임 — P2~P5 일괄 진행 지시). 로드맵 P3/5. ## 1. 목표 (사용자 요구) 1. **카드 드래그→몬스터 지정**: 카드를 끌어 특정 몬스터에 놓아 사용(클릭 대체). 2. **공격 모션 후 데미지**: 공격 카드 사용 시 연출(스킬 이펙트) 후 몬스터가 피해. 3. **몬스터 개별 차례**: 적 턴에 몬스터가 한 마리씩 순서대로 행동(행동자 표시). 4. 데미지 숫자 표시·사망 연출 등 게임필 보강. ## 2. 타당성 (probe 완료) - `maker_mouse_input` down → `ScreenTouchEvent` 발화 + `ScreenToUIPosition` 변환 실측 일치(카드2 위치). - **`MOD.Core.UITouchReceiveComponent`**: UI 엔티티에 부착 시 `UITouchBeginDragEvent`/`UITouchDragEvent`/`UITouchEndDragEvent`/`UITouchDownEvent`/`UITouchUpEvent` 제공(공식, Client). 드래그는 이걸 사용. - 몬스터 world→screen(`_UILogic:WorldToScreenPosition`)은 P1에서 검증됨 — 드롭 판정에 재사용. ## 3. 설계 ### 3.1 카드 드래그 타겟팅 - 손패 Card1~5 엔티티에 `MOD.Core.UITouchReceiveComponent` 추가(생성기 componentNames+컴포넌트). - 컨트롤러 상태: `DragSlot`(0=없음), `DragOrigin`(원위치 Vector2), `DragMoved`(boolean). - `BindButtons`에서 카드별로 connect: - `UITouchBeginDragEvent` → CombatOver 아니고 손패에 카드 있으면 `DragSlot=i`, 원위치 저장(`CARD_XS[i]` 상수로 복원 가능하므로 저장은 단순화 가능 — 원위치 = (CARD_XS[i], 0)). - `UITouchDragEvent` → 카드 `anchoredPosition = ScreenToUIPosition(TouchPoint) - CardHandOffset` (CardHand 부모 중심의 UI 좌표 보정값은 런타임 계산: 카드 부모 CardHand의 화면상 중심 = UI(0, -360) → 보정 상수로 굽기). - `UITouchEndDragEvent` → `ResolveCardDrop(i, TouchPoint)` 후 카드 위치 복원. - `ResolveCardDrop(slot, screenPoint)`: - 카드 kind 조회. **Attack**: 생존 몬스터 중 화면 거리(몬스터 world→screen vs screenPoint) 최소이고 임계(예: 200px) 이내인 몬스터 → `SetTarget(그 몬스터)` 후 `PlayCard(slot)`. 임계 밖이면 취소(복귀만). - **Skill**: 드롭 위치가 손패 위(화면 y 기준 카드 영역 위쪽, 예: screen y > 화면 40%)면 `PlayCard(slot)`, 아니면 취소. - 기존 카드 ButtonComponent 클릭 `PlayCard` 바인딩 **제거**(드래그와 충돌 방지, 사용은 드래그로 일원화 — STS 방식). 몬스터 슬롯 클릭 SetTarget은 유지(타겟만 바꾸는 보조 수단). ### 3.2 공격 연출 → 데미지 (PlayCard Attack 시퀀스) - `CombatHud/SkillFx` 엔티티 1개(96×96 이미지 스프라이트, 평소 숨김). - PlayCard(Attack) 흐름 변경: 에너지 차감·손패 제거·렌더는 즉시, **데미지는 지연**: 1. `ShowSkillFx(targetIndex, c.image)`: 타겟 몬스터 world→screen 위치에 SkillFx 표시(ImageRUID=카드 이미지). 2. 0.35s 타이머 → SkillFx 숨김 + `DealDamageToTarget(damage)` + 데미지 팝업 + RenderCombat + CheckCombatEnd. - 연출 중 입력 보호: `FxBusy=true` 동안 PlayCard/EndPlayerTurn 무시(0.35s). ### 3.3 데미지 숫자 팝업 - `MonsterSlot{i}/DmgPop`(텍스트, 숨김 기본): `ShowDmgPop(slot, amount)` — "-N" 표시 → 0.6s 후 숨김(타이머; 위치 고정 단순화). - `PlayerPanel/DmgPop` 동일(적 공격 시 "-N", 방어 흡수로 0이면 "막음"). ### 3.4 적 개별 차례 (EnemyTurn 시퀀스화) - `EnemyTurn` → 비동기 체인으로 재작성: - `EnemyActIndex=0`; `EnemyActStep()`: 다음 생존 몬스터 찾기 → 없으면 `FinishEnemyTurn()`. - 행동 몬스터 슬롯에 `ActFrame`(적색 하이라이트 — TargetFrame과 별도 자식, 156×108 적색 a0.3) 표시 → 0.45s 타이머 → 의도 적용(Attack: DealDamageToPlayer+플레이어 DmgPop / Defend: block+슬롯 의도 갱신) → ActFrame 숨김 → 다음 `EnemyActStep()` (0.15s 간격). - 플레이어 사망 시 즉시 `FinishEnemyTurn()`. - `FinishEnemyTurn()`: `CheckCombatEnd` 후 미종료면 0.45s 뒤 `StartPlayerTurn`(기존 EndPlayerTurn 후반부 이동). - `EndPlayerTurn`: 손패 버림+렌더 후 `EnemyTurn()` 호출로 종료(후속 로직은 FinishEnemyTurn으로 이동). `TurnBusy=true`로 적 턴 중 입력 차단(FxBusy와 함께 가드). ### 3.5 사망 연출 - `KillMonster`: 즉시 SetVisible(false) → **0.4s 지연**으로 변경(DmgPop과 겹쳐 보이게), 슬롯 비활성은 즉시 유지. ## 4. 검증 - 생성 결정성·dup 0·sim 14/14(규칙 불변 — 연출 지연만 추가, 데미지 계산 동일). - 메이커: ①카드를 몬스터2에 드래그→타겟 변경+이펙트→데미지 팝업→HP 감소 ②Skill 카드 위로 드래그→방어 ③드롭 취소(빈 곳) ④턴 종료→적들이 한 마리씩 순차 행동(ActFrame 이동)+플레이어 팝업 ⑤전체 처치 승리 정상. ## 5. 리스크 - UITouchReceiveComponent와 ButtonComponent 공존(슬롯 클릭/드래그 간섭) — 카드에서 Button 제거하므로 카드는 안전; 몬스터 슬롯은 Button 유지(드래그 없음). - UITouchDragEvent 빈도/좌표계 — 구현 후 메이커 검증(§4①). 드래그 좌표 보정 상수는 실측 튜닝. - 비동기 체인 중 상태 변화(연출 중 사망 등) — FxBusy/TurnBusy 가드 + 각 스텝에서 alive/CombatOver 재확인.