This commit is contained in:
Horoli 2025-12-08 03:00:45 +09:00
parent 9540dd22a3
commit eab99eee6f
1 changed files with 33 additions and 11 deletions

View File

@ -4,33 +4,55 @@
* 플레이어 공격 실패(`MISS`) 시, 화면에 `MISS` 텍스트가 두 번 올라오는 현상 발생.
* 적의 방어 실패(`FAILED`) 시에도 유사한 중복 텍스트 현상 발생.
* 로그상 (`[UI Debug] Feedback Event`)으로는 이벤트가 한 번만 발생했지만, UI에는 두 번 표시됨.
* `_addFloatingEffect` 함수 내부에 `eventId` 기반의 중복 체크 로직이 추가되었음에도 현상 지속.
* 특히, "적이 방어 행동(Action Phase, Phase 1)을 했을 때만" 문제가 발생한다고 특정됨.
## 2. 진단 및 해결 시도
### 2.1. 원인 가설
1. **`BattleScreen` 인스턴스 중복:** 가장 유력한 가설. 하나의 `EffectEvent`가 발생했을 때, 여러 `BattleScreen` 인스턴스가 각자 이벤트를 받아 화면에 피드백 텍스트를 띄우는 경우.
* `[UI Debug] BattleScreen initialized: ${hashCode}` 로그로 확인 필요. (현재 확인되지 않음)
2. **`_addFloatingEffect` 내부의 `setState` 문제:** `setState` 호출 시 `_floatingFeedbackTexts` 리스트에 위젯이 중복으로 추가되거나, 위젯 렌더링 과정에서 불필요한 복제가 발생하는 경우. (리스트 `clear()` 로직 추가로 해결 시도 중)
* `[UI Debug] BattleScreen initialized: ${hashCode}` 로그로 확인 필요. **현재 로그에서는 단 한 번만 찍히는 것으로 보이나, 화면에는 중복 현상이 발생하고 있음.** 이는 `BattleScreen` 인스턴스 자체의 중복보다는, **동일 인스턴스 내에서의 렌더링 또는 이벤트 처리 문제**임을 시사.
2. **`_addFloatingEffect` 내부의 `setState` 문제 / `FloatingFeedbackText` 위젯의 생명주기 문제:** `setState` 호출 시 `_floatingFeedbackTexts` 리스트에 위젯이 중복으로 추가되거나, 위젯 렌더링 과정에서 불필요한 복제가 발생하는 경우.
* `_floatingFeedbackTexts.clear()` 로직 도입 및 `eventId` 기반 중복 체크로 리스트 데이터 중복은 해결. 그러나 화면상 중복 표시는 지속.
3. **UI 렌더링 타이밍/시각적 착시:** `FloatingFeedbackText` 위젯의 생명주기가 꼬여서 이전 텍스트가 완전히 사라지기 전에 새 텍스트가 뜨거나, 애니메이션이 반복되는 것처럼 보이는 착시.
### 2.2. 현재까지 적용된 주요 조치
#### **A. 피드백 텍스트 중복 출력 방지 및 디버깅 강화**
* **`EffectEvent` `eventId` 기반 중복 체크 (UI 레벨):** `_addFloatingEffect` 함수에서 `eventId`를 기반으로 동일한 이벤트에 대한 피드백 텍스트가 이미 리스트에 있다면 추가하지 않도록 `_floatingFeedbackTexts.any((e) => e.eventId == event.id)` 로직 추가.
* **`_floatingFeedbackTexts.clear()` 도입:** 새로운 피드백 텍스트(`MISS`/`FAILED`)가 뜰 때, 기존의 모든 피드백 텍스트를 리스트에서 제거한 후 추가하도록 수정. (화면에 항상 하나의 피드백 텍스트만 유지)
* **`_floatingFeedbackTexts.clear()` 도입:** 새로운 피드백 텍스트(`MISS`/`FAILED`)가 뜰 때, 기존의 모든 피드백 텍스트를 리스트에서 제거한 후 추가하도록 수정. (화면에 항상 하나의 피드백 텍스트만 유지).
* **`addPostFrameCallback` 제거:** `_addFloatingEffect``WidgetsBinding.instance.addPostFrameCallback` 제거 (불필요한 비동기 지연 및 잠재적 문제 방지).
* **디버그 로그 추가:**
* `[UI Debug] BattleScreen initialized: ${hashCode}` (`BattleScreen` 초기화 횟수 확인용)
* `[UI Debug] Feedback Event: ${event.id}, Type: ${event.feedbackType}` (`_addFloatingEffect` 호출 확인용)
* `FloatingFeedbackText``event.id` 전체 표시 (화면상 ID 일치 여부 확인용)
* `[UI Debug] BattleScreen initialized: ${hashCode}` (`BattleScreen` 초기화 횟수 확인용. **로그상 1회**).
* `[UI Debug] Feedback Event: ${event.id}, Type: ${event.feedbackType}` (`_addFloatingEffect` 호출 확인용. **로그상 1회**).
* `FloatingFeedbackText``event.id` 전체 표시 (화면상 ID 일치 여부 확인용).
* `[Logic Debug]` 로그 추가 (`BattleProvider` 이벤트 발행 시점 확인용).
#### **B. 비동기 턴 흐름 안정화 (Transaction ID 패턴)**
* **`_turnTransactionId` 패턴 도입:** `BattleProvider``int _turnTransactionId`를 추가하여 턴 전환 시 ID를 증가시키고, 모든 `Future.delayed` 콜백 내에서 ID를 체크하여 이전 턴의 "좀비 타이머"가 다음 턴 로직을 침범하지 않도록 방지.
#### **C. 적의 방어 행동 타이밍 및 시각화 개선**
* **방어도 계산식 수정:** `_generateEnemyIntent`에서 `baseDef * 2` 상수를 제거하여 `Risky` 방어가 과도하게 적용되지 않도록 수정.
* **"Just-in-Time" 방어 도입:** 플레이어가 공격하기 직전(`playerAction` 시작 시)에 적이 방어(성공/실패) 행동을 발동하고, 500ms 딜레이 후 플레이어 공격 로직 진행.
* **방어 애니메이션 추가:** `BattleAnimationWidget``animateDefense` 메서드 추가 (좌우 흔들림).
* **`_addFloatingEffect` 로직 통합:**
* `showEffect`는 순수 UI만 담당 (딜레이, `handleImpact` 호출 제거).
* 공격/방어 애니메이션은 성공/실패 모두 실행. (`animateAttack` 또는 `animateDefense`).
* `MISS`/`FAILED` 시에는 500ms 딜레이 후 `handleImpact`.
* 적/플레이어 공격 `MISS``RiskLevel.safe` 애니메이션 강제.
* 적 공격 애니메이션 중 `intent` 정보 숨김.
* **Phase 1 방어 행동 시 딜레이 조절:** `skipAnimations` 설정에 따라 딜레이(1.5초 또는 0.5초) 적용.
## 3. 남아있는 문제 (현재 진단)
* 로그상 `[UI Debug] Feedback Event`는 한 번만 찍히지만, **화면에는 `MISS` 텍스트가 두 번 표시됨.**
* 이는 **UI 레벨에서의 렌더링 문제**이거나, `_addFloatingEffect` 함수 **내부 로직 중 `setState`가 비정상적으로 두 번 호출**되는 문제일 가능성이 높습니다.
* `_floatingFeedbackTexts.clear()` 로직이 추가되었으므로, 같은 리스트에 두 번 추가되는 것은 막혔을 것입니다.
* **`[UI Debug] BattleScreen initialized` 로그도 1회만 찍히므로 `BattleScreen` 인스턴스 중복은 아님.**
* 이벤트가 두 번 발행되거나 `_addFloatingEffect` 함수가 두 번 호출되는 것도 아님. (로그 증거).
* `_floatingFeedbackTexts.clear()` 로직 도입으로 리스트에 두 번 추가될 수도 없음.
* **가장 유력한 가설:** `_addFloatingEffect` 내부의 `setState`가 호출된 후, Flutter의 위젯 트리 리빌드 및 렌더링 과정에서 **`FloatingFeedbackText` 위젯이 어떤 이유로 인해 화면에 두 번 그려지거나 (복제되거나), 또는 렌더링 과정에서 잔상이 남아 두 번으로 보이는 것.**
* 이것은 Flutter의 렌더링 파이프라인이나 `Stack` / `Positioned` 위젯의 상호작용과 관련된 심도 깊은 UI 버그일 가능성이 높음.
## 4. 다음 단계 제안
* **`[UI Debug] BattleScreen initialized: ...` 로그 결과 확인:** 이 로그가 두 번 이상 찍힌다면 `BattleScreen` 인스턴스가 중복된 것이므로, `MainWrapper`나 라우팅 구조를 점검해야 합니다.
* **화면상 `MISS` 텍스트의 ID 확인:** 화면에 보이는 두 개의 `MISS` 텍스트의 ID가 **정확히 동일한지** 확인 필요 (현재 `event.id` 전체를 표시하도록 수정됨).
* **ID가 동일하다면:** 하나의 `FeedbackTextData` 객체가 UI에 중복 렌더링되는 문제. (Key 문제, `Stack` 리빌드 문제 등)
* **ID가 다르다면:** `_addFloatingEffect` 자체가 두 번 호출된 것. (로그가 하나라는 것과 모순됨. 로그 시스템 확인 필요)
* **Flutter DevTools (Inspector) 활용:** 다른 환경에서 `Widget Inspector`를 통해 `Stack` 아래에 `FloatingFeedbackText` 위젯이 실제로 몇 개나 존재하는지 확인하는 것이 가장 정확합니다.
**현재까지의 모든 문제 해결 노력은 `BattleProvider` 내의 로직 중복이나 타이밍 오류를 잡는 데 초점을 맞췄습니다. 하지만 `MISS` 텍스트 중복 문제는 `BattleScreen` (UI) 쪽에서 발생하는 현상으로 보입니다.**