feat(animation): 공격 속도 기반 동적 애니메이션 페이즈
- CombatEvent에 attackDelayMs 필드 추가 - ProgressService에서 전투 이벤트에 공격 속도 전달 - AsciiAnimationCard에서 공격 속도 기반 페이즈 프레임 수 계산 - 200ms tick 기준으로 동적 프레임 수 (최소 2, 최대 10)
This commit is contained in:
@@ -1118,6 +1118,7 @@ class ProgressService {
|
|||||||
skillName: selectedSkill.name,
|
skillName: selectedSkill.name,
|
||||||
damage: skillResult.result.damage,
|
damage: skillResult.result.damage,
|
||||||
targetName: monsterStats.name,
|
targetName: monsterStats.name,
|
||||||
|
attackDelayMs: playerStats.attackDelayMs,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else if (selectedSkill != null && selectedSkill.isDot) {
|
} else if (selectedSkill != null && selectedSkill.isDot) {
|
||||||
@@ -1144,6 +1145,7 @@ class ProgressService {
|
|||||||
skillName: selectedSkill.name,
|
skillName: selectedSkill.name,
|
||||||
damage: skillResult.result.damage,
|
damage: skillResult.result.damage,
|
||||||
targetName: monsterStats.name,
|
targetName: monsterStats.name,
|
||||||
|
attackDelayMs: playerStats.attackDelayMs,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else if (selectedSkill != null && selectedSkill.isHeal) {
|
} else if (selectedSkill != null && selectedSkill.isHeal) {
|
||||||
@@ -1206,6 +1208,7 @@ class ProgressService {
|
|||||||
damage: result.damage,
|
damage: result.damage,
|
||||||
targetName: monsterStats.name,
|
targetName: monsterStats.name,
|
||||||
isCritical: result.isCritical,
|
isCritical: result.isCritical,
|
||||||
|
attackDelayMs: playerStats.attackDelayMs,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1257,6 +1260,7 @@ class ProgressService {
|
|||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
damage: result.damage,
|
damage: result.damage,
|
||||||
attackerName: monsterStats.name,
|
attackerName: monsterStats.name,
|
||||||
|
attackDelayMs: monsterStats.attackDelayMs,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class CombatEvent {
|
|||||||
this.isCritical = false,
|
this.isCritical = false,
|
||||||
this.skillName,
|
this.skillName,
|
||||||
this.targetName,
|
this.targetName,
|
||||||
|
this.attackDelayMs,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// 이벤트 타입
|
/// 이벤트 타입
|
||||||
@@ -72,12 +73,17 @@ class CombatEvent {
|
|||||||
/// 대상 이름 (몬스터 또는 플레이어)
|
/// 대상 이름 (몬스터 또는 플레이어)
|
||||||
final String? targetName;
|
final String? targetName;
|
||||||
|
|
||||||
|
/// 공격자의 공격 속도 (ms)
|
||||||
|
/// 애니메이션 페이즈 지속 시간 계산에 사용
|
||||||
|
final int? attackDelayMs;
|
||||||
|
|
||||||
/// 플레이어 공격 이벤트 생성
|
/// 플레이어 공격 이벤트 생성
|
||||||
factory CombatEvent.playerAttack({
|
factory CombatEvent.playerAttack({
|
||||||
required int timestamp,
|
required int timestamp,
|
||||||
required int damage,
|
required int damage,
|
||||||
required String targetName,
|
required String targetName,
|
||||||
bool isCritical = false,
|
bool isCritical = false,
|
||||||
|
int? attackDelayMs,
|
||||||
}) {
|
}) {
|
||||||
return CombatEvent(
|
return CombatEvent(
|
||||||
type: CombatEventType.playerAttack,
|
type: CombatEventType.playerAttack,
|
||||||
@@ -85,6 +91,7 @@ class CombatEvent {
|
|||||||
damage: damage,
|
damage: damage,
|
||||||
targetName: targetName,
|
targetName: targetName,
|
||||||
isCritical: isCritical,
|
isCritical: isCritical,
|
||||||
|
attackDelayMs: attackDelayMs,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,12 +100,14 @@ class CombatEvent {
|
|||||||
required int timestamp,
|
required int timestamp,
|
||||||
required int damage,
|
required int damage,
|
||||||
required String attackerName,
|
required String attackerName,
|
||||||
|
int? attackDelayMs,
|
||||||
}) {
|
}) {
|
||||||
return CombatEvent(
|
return CombatEvent(
|
||||||
type: CombatEventType.monsterAttack,
|
type: CombatEventType.monsterAttack,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
damage: damage,
|
damage: damage,
|
||||||
targetName: attackerName,
|
targetName: attackerName,
|
||||||
|
attackDelayMs: attackDelayMs,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +170,7 @@ class CombatEvent {
|
|||||||
required int damage,
|
required int damage,
|
||||||
required String targetName,
|
required String targetName,
|
||||||
bool isCritical = false,
|
bool isCritical = false,
|
||||||
|
int? attackDelayMs,
|
||||||
}) {
|
}) {
|
||||||
return CombatEvent(
|
return CombatEvent(
|
||||||
type: CombatEventType.playerSkill,
|
type: CombatEventType.playerSkill,
|
||||||
@@ -169,6 +179,7 @@ class CombatEvent {
|
|||||||
damage: damage,
|
damage: damage,
|
||||||
targetName: targetName,
|
targetName: targetName,
|
||||||
isCritical: isCritical,
|
isCritical: isCritical,
|
||||||
|
attackDelayMs: attackDelayMs,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,10 @@ class _AsciiAnimationCardState extends State<AsciiAnimationCard> {
|
|||||||
bool _showParryEffect = false;
|
bool _showParryEffect = false;
|
||||||
bool _showSkillEffect = false;
|
bool _showSkillEffect = false;
|
||||||
|
|
||||||
|
// 공격 속도 기반 동적 페이즈 프레임 수 (Phase 6)
|
||||||
|
int _eventDrivenPhaseFrames = 0;
|
||||||
|
bool _isEventDrivenPhase = false;
|
||||||
|
|
||||||
// 특수 애니메이션 프레임 수는 ascii_animation_type.dart의
|
// 특수 애니메이션 프레임 수는 ascii_animation_type.dart의
|
||||||
// specialAnimationFrameCounts 상수 사용
|
// specialAnimationFrameCounts 상수 사용
|
||||||
|
|
||||||
@@ -318,6 +322,15 @@ class _AsciiAnimationCardState extends State<AsciiAnimationCard> {
|
|||||||
// 페이즈 인덱스 동기화
|
// 페이즈 인덱스 동기화
|
||||||
_phaseIndex = _battlePhaseSequence.indexWhere((p) => p.$1 == targetPhase);
|
_phaseIndex = _battlePhaseSequence.indexWhere((p) => p.$1 == targetPhase);
|
||||||
if (_phaseIndex < 0) _phaseIndex = 0;
|
if (_phaseIndex < 0) _phaseIndex = 0;
|
||||||
|
|
||||||
|
// 공격 속도에 따른 동적 페이즈 프레임 수 계산 (Phase 6)
|
||||||
|
// 200ms tick 기준으로 프레임 수 계산 (최소 2, 최대 10)
|
||||||
|
if (event.attackDelayMs != null && event.attackDelayMs! > 0) {
|
||||||
|
_eventDrivenPhaseFrames = (event.attackDelayMs! ~/ 200).clamp(2, 10);
|
||||||
|
_isEventDrivenPhase = true;
|
||||||
|
} else {
|
||||||
|
_isEventDrivenPhase = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,8 +447,14 @@ class _AsciiAnimationCardState extends State<AsciiAnimationCard> {
|
|||||||
_phaseFrameCount++;
|
_phaseFrameCount++;
|
||||||
final currentPhase = _battlePhaseSequence[_phaseIndex];
|
final currentPhase = _battlePhaseSequence[_phaseIndex];
|
||||||
|
|
||||||
|
// 현재 페이즈의 프레임 수 결정 (Phase 6)
|
||||||
|
// 이벤트 기반 페이즈일 경우 공격 속도에 따른 동적 프레임 수 사용
|
||||||
|
final targetFrames = _isEventDrivenPhase
|
||||||
|
? _eventDrivenPhaseFrames
|
||||||
|
: currentPhase.$2;
|
||||||
|
|
||||||
// 현재 페이즈의 프레임 수를 초과하면 다음 페이즈로
|
// 현재 페이즈의 프레임 수를 초과하면 다음 페이즈로
|
||||||
if (_phaseFrameCount >= currentPhase.$2) {
|
if (_phaseFrameCount >= targetFrames) {
|
||||||
_phaseIndex = (_phaseIndex + 1) % _battlePhaseSequence.length;
|
_phaseIndex = (_phaseIndex + 1) % _battlePhaseSequence.length;
|
||||||
_phaseFrameCount = 0;
|
_phaseFrameCount = 0;
|
||||||
_battleSubFrame = 0;
|
_battleSubFrame = 0;
|
||||||
@@ -444,6 +463,8 @@ class _AsciiAnimationCardState extends State<AsciiAnimationCard> {
|
|||||||
_showBlockEffect = false;
|
_showBlockEffect = false;
|
||||||
_showParryEffect = false;
|
_showParryEffect = false;
|
||||||
_showSkillEffect = false;
|
_showSkillEffect = false;
|
||||||
|
// 이벤트 기반 페이즈 종료
|
||||||
|
_isEventDrivenPhase = false;
|
||||||
} else {
|
} else {
|
||||||
_battleSubFrame++;
|
_battleSubFrame++;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user