Compare commits

...

2 Commits

Author SHA1 Message Date
JiWoong Sul
17ab73758a fix(equipment): 기본 무기에 attackSpeed 추가
- bareHands 무기에 attackSpeed: 1000 기본값 설정
2025-12-26 19:29:43 +09:00
JiWoong Sul
28cf5fa687 fix(animation): 전투 애니메이션 위치 및 이펙트 개선
- 캐릭터/몬스터 hit/attack 페이즈 위치 버그 수정
- 이펙트 위치를 캐릭터/몬스터 위치에 따라 동적 계산
- 이벤트 기반 페이즈 리셋을 idle 진입 시에만 수행
2025-12-26 19:29:38 +09:00
3 changed files with 40 additions and 13 deletions

View File

@@ -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<String> 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;

View File

@@ -66,7 +66,7 @@ class EquipmentItem {
slot: EquipmentSlot.weapon,
level: 1,
weight: 5,
stats: ItemStats(atk: 1),
stats: ItemStats(atk: 1, attackSpeed: 1000),
rarity: ItemRarity.common,
);
}

View File

@@ -474,12 +474,11 @@ class _AsciiAnimationCardState extends State<AsciiAnimationCard> {
_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++;