From 28cf5fa687098e076e478befb55997ee09b8a2d9 Mon Sep 17 00:00:00 2001 From: JiWoong Sul Date: Fri, 26 Dec 2025 19:29:38 +0900 Subject: [PATCH] =?UTF-8?q?fix(animation):=20=EC=A0=84=ED=88=AC=20?= =?UTF-8?q?=EC=95=A0=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EB=B0=8F=20=EC=9D=B4=ED=8E=99=ED=8A=B8=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 캐릭터/몬스터 hit/attack 페이즈 위치 버그 수정 - 이펙트 위치를 캐릭터/몬스터 위치에 따라 동적 계산 - 이벤트 기반 페이즈 리셋을 idle 진입 시에만 수행 --- .../canvas/canvas_battle_composer.dart | 44 +++++++++++++++---- .../game/widgets/ascii_animation_card.dart | 7 ++- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/lib/src/core/animation/canvas/canvas_battle_composer.dart b/lib/src/core/animation/canvas/canvas_battle_composer.dart index 49c8555..269ecbc 100644 --- a/lib/src/core/animation/canvas/canvas_battle_composer.dart +++ b/lib/src/core/animation/canvas/canvas_battle_composer.dart @@ -137,11 +137,12 @@ class CanvasBattleComposer { // 페이즈별 X 위치 (Phase 7: 공격자별 위치 분리) // 플레이어가 공격자일 때만 이동, 아니면 제자리(12) + // hit 페이즈에서도 플레이어 공격 중이면 위치 유지 (Bug fix) final charX = switch (phase) { BattlePhase.idle => 12, BattlePhase.prepare => isPlayerAttacking ? 15 : 12, BattlePhase.attack => isPlayerAttacking ? 18 : 12, - BattlePhase.hit => attacker == AttackerType.both ? 18 : 12, + BattlePhase.hit => isPlayerAttacking ? 18 : 12, BattlePhase.recover => isPlayerAttacking ? 15 : 12, }; @@ -181,10 +182,11 @@ class CanvasBattleComposer { // 페이즈별 X 위치 (Phase 7: 공격자별 위치 분리) // 몬스터가 공격자일 때만 이동, 아니면 제자리(48) + // attack 페이즈에서도 몬스터 공격 중이면 위치 유지 (Bug fix) final monsterRightEdge = switch (phase) { BattlePhase.idle => 48, BattlePhase.prepare => isMonsterAttacking ? 45 : 48, - BattlePhase.attack => attacker == AttackerType.both ? 42 : 48, + BattlePhase.attack => isMonsterAttacking ? 42 : 48, BattlePhase.hit => isMonsterAttacking ? 42 : 48, BattlePhase.recover => isMonsterAttacking ? 45 : 48, }; @@ -211,24 +213,50 @@ class CanvasBattleComposer { int subFrame, AttackerType attacker, ) { + // 공격자별 위치 계산을 위한 플래그 (동일 로직 재사용) + final isPlayerAttacking = + attacker == AttackerType.player || attacker == AttackerType.both; + final isMonsterAttacking = + attacker == AttackerType.monster || attacker == AttackerType.both; + + // 캐릭터 위치 계산 (characterLayer와 동일 로직) + const charWidth = 6; + final charX = switch (phase) { + BattlePhase.idle => 12, + BattlePhase.prepare => isPlayerAttacking ? 15 : 12, + BattlePhase.attack => isPlayerAttacking ? 18 : 12, + BattlePhase.hit => isPlayerAttacking ? 18 : 12, + BattlePhase.recover => isPlayerAttacking ? 15 : 12, + }; + + // 몬스터 위치 계산 (monsterLayer와 동일 로직) + final monsterRightEdge = switch (phase) { + BattlePhase.idle => 48, + BattlePhase.prepare => isMonsterAttacking ? 45 : 48, + BattlePhase.attack => isMonsterAttacking ? 42 : 48, + BattlePhase.hit => isMonsterAttacking ? 42 : 48, + BattlePhase.recover => isMonsterAttacking ? 45 : 48, + }; + final monsterX = monsterRightEdge - monsterWidth; + // 공격자에 따라 다른 이펙트 사용 final List effectLines; final int effectX; if (attacker == AttackerType.player) { - // 플레이어 공격: 무기 이펙트 → 몬스터 왼쪽 + // 플레이어 공격: 무기 이펙트 → 몬스터 왼쪽 바로 옆 final effect = getWeaponEffect(weaponCategory); effectLines = _getEffectLines(effect, phase, subFrame); - effectX = 28; + effectX = monsterX - 2; } else if (attacker == AttackerType.monster) { - // 몬스터 공격: 왼쪽 방향 이펙트 → 캐릭터 오른쪽 + // 몬스터 공격: 왼쪽 방향 이펙트 → 캐릭터 오른쪽 바로 옆 effectLines = _getMonsterAttackEffect(phase, subFrame); - effectX = 18; + effectX = charX + charWidth; } else { - // 동시 공격(both): 무기 이펙트 중앙 표시 + // 동시 공격(both): 무기 이펙트 두 캐릭터 중앙 final effect = getWeaponEffect(weaponCategory); effectLines = _getEffectLines(effect, phase, subFrame); - effectX = 23; + effectX = (charX + charWidth + monsterX) ~/ 2; } if (effectLines.isEmpty) return null; diff --git a/lib/src/features/game/widgets/ascii_animation_card.dart b/lib/src/features/game/widgets/ascii_animation_card.dart index 50816b7..a8812ac 100644 --- a/lib/src/features/game/widgets/ascii_animation_card.dart +++ b/lib/src/features/game/widgets/ascii_animation_card.dart @@ -474,12 +474,11 @@ class _AsciiAnimationCardState extends State { _showBlockEffect = false; _showParryEffect = false; _showSkillEffect = false; - // 이벤트 기반 페이즈 종료 - _isEventDrivenPhase = false; - // 공격자 타입 리셋 (idle 페이즈 진입 시에만) - // 공격 사이클(prepare→attack→hit→recover) 동안 유지 + // 공격자 타입 및 이벤트 기반 페이즈 리셋 (idle 페이즈 진입 시에만) + // 공격 사이클(prepare→attack→hit→recover) 동안 유지 (Bug fix) if (_battlePhaseSequence[_phaseIndex].$1 == BattlePhase.idle) { _currentAttacker = AttackerType.none; + _isEventDrivenPhase = false; } } else { _battleSubFrame++;