update
This commit is contained in:
@@ -53,8 +53,13 @@ class BattleAnimationWidgetState extends State<BattleAnimationWidget>
|
||||
Future<void> animateAttack(
|
||||
Offset targetOffset,
|
||||
VoidCallback onImpact,
|
||||
RiskLevel risk,
|
||||
) async {
|
||||
RiskLevel risk, {
|
||||
VoidCallback? onAnimationStart,
|
||||
VoidCallback? onAnimationMiddle,
|
||||
VoidCallback? onAnimationEnd,
|
||||
}) async {
|
||||
// onAnimationStart?.call(); // Start Phase
|
||||
|
||||
if (risk == RiskLevel.safe || risk == RiskLevel.normal) {
|
||||
// Safe & Normal: Dash/Wobble without scale
|
||||
final isSafe = risk == RiskLevel.safe;
|
||||
@@ -75,9 +80,13 @@ class BattleAnimationWidgetState extends State<BattleAnimationWidget>
|
||||
|
||||
await _translateController.forward();
|
||||
if (!mounted) return;
|
||||
|
||||
// onAnimationMiddle?.call(); // Middle Phase
|
||||
onImpact();
|
||||
|
||||
await _translateController.reverse();
|
||||
} else {
|
||||
onAnimationStart?.call(); // Start Phase
|
||||
// Risky: Scale + Heavy Dash
|
||||
final attackScale = context.read<SettingsProvider>().attackAnimScale;
|
||||
_scaleAnimation = Tween<double>(begin: 1.0, end: attackScale).animate(
|
||||
@@ -91,6 +100,8 @@ class BattleAnimationWidgetState extends State<BattleAnimationWidget>
|
||||
await _scaleController.forward();
|
||||
if (!mounted) return;
|
||||
|
||||
onAnimationMiddle?.call(); // Middle Phase
|
||||
|
||||
// 2. Dash to Target (Impact)
|
||||
// Adjust offset to prevent complete overlap (stop slightly short) since both share the same layer stack
|
||||
final adjustedOffset = targetOffset * 0.5;
|
||||
@@ -106,13 +117,17 @@ class BattleAnimationWidgetState extends State<BattleAnimationWidget>
|
||||
await _translateController.forward();
|
||||
if (!mounted) return;
|
||||
|
||||
// onAnimationEnd?.call(); // End Phase (Moved before Impact)
|
||||
|
||||
// 3. Impact Callback (Shake)
|
||||
onImpact();
|
||||
|
||||
// 4. Return (Reset)
|
||||
_scaleController.reverse();
|
||||
_translateController.reverse();
|
||||
await _translateController.reverse();
|
||||
}
|
||||
|
||||
// onAnimationEnd removed from here
|
||||
}
|
||||
|
||||
Future<void> animateDefense(VoidCallback onImpact) async {
|
||||
|
||||
@@ -12,6 +12,7 @@ class CharacterStatusCard extends StatelessWidget {
|
||||
final bool isTurn;
|
||||
final GlobalKey<BattleAnimationWidgetState>? animationKey;
|
||||
final bool hideStats;
|
||||
final String? overrideImage;
|
||||
|
||||
const CharacterStatusCard({
|
||||
super.key,
|
||||
@@ -20,6 +21,7 @@ class CharacterStatusCard extends StatelessWidget {
|
||||
this.isTurn = false,
|
||||
this.animationKey,
|
||||
this.hideStats = false,
|
||||
this.overrideImage,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -51,7 +53,7 @@ class CharacterStatusCard extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 100,
|
||||
width: ThemeConfig.playerImageSize,
|
||||
child: LinearProgressIndicator(
|
||||
value: character.totalMaxHp > 0
|
||||
? character.hp / character.totalMaxHp
|
||||
@@ -84,7 +86,7 @@ class CharacterStatusCard extends StatelessWidget {
|
||||
"${effect.type.name.toUpperCase()} (${effect.duration})",
|
||||
style: const TextStyle(
|
||||
color: ThemeConfig.effectText,
|
||||
fontSize: 10,
|
||||
fontSize: ThemeConfig.statusEffectFontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
@@ -92,64 +94,51 @@ class CharacterStatusCard extends StatelessWidget {
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
// Text(
|
||||
// "ATK: ${character.totalAtk}",
|
||||
// style: const TextStyle(color: ThemeConfig.textColorWhite),
|
||||
// ),
|
||||
// Text(
|
||||
// "DEF: ${character.totalDefense}",
|
||||
// style: const TextStyle(color: ThemeConfig.textColorWhite),
|
||||
// ),
|
||||
// Text(
|
||||
// "LUCK: ${character.totalLuck}",
|
||||
// style: const TextStyle(color: ThemeConfig.textColorWhite),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8), // 아이콘과 정보 사이 간격
|
||||
// 캐릭터 아이콘/이미지 영역 추가
|
||||
const SizedBox(height: 8),
|
||||
BattleAnimationWidget(
|
||||
key: animationKey,
|
||||
child: Container(
|
||||
width: isPlayer ? 100 : 200, // 플레이어 100, 적 200
|
||||
height: isPlayer ? 100 : 200, // 플레이어 100, 적 200
|
||||
width: isPlayer
|
||||
? ThemeConfig.playerImageSize
|
||||
: ThemeConfig.enemyImageSize,
|
||||
height: isPlayer
|
||||
? ThemeConfig.playerImageSize
|
||||
: ThemeConfig.enemyImageSize,
|
||||
decoration: BoxDecoration(
|
||||
color: isPlayer ? Colors.lightBlue : null,
|
||||
// color: isPlayer ? ThemeConfig.playerImageBgColor : null,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Center(
|
||||
child: isPlayer
|
||||
? const Icon(
|
||||
Icons.person,
|
||||
size: 60,
|
||||
color: ThemeConfig.textColorWhite,
|
||||
) // 플레이어 아이콘
|
||||
: (character.image != null && character.image!.isNotEmpty)
|
||||
child: (overrideImage != null ||
|
||||
(character.image != null && character.image!.isNotEmpty))
|
||||
? Image.asset(
|
||||
character.image!,
|
||||
width: 200,
|
||||
height: 200,
|
||||
overrideImage ?? character.image!,
|
||||
width: isPlayer
|
||||
? ThemeConfig.playerImageSize
|
||||
: ThemeConfig.enemyImageSize,
|
||||
height: isPlayer
|
||||
? ThemeConfig.playerImageSize
|
||||
: ThemeConfig.enemyImageSize,
|
||||
fit: BoxFit.contain,
|
||||
// color: Colors.white,
|
||||
// colorBlendMode: BlendMode.screen,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return const Icon(
|
||||
Icons.psychology,
|
||||
size: 60,
|
||||
Icons.error_outline,
|
||||
size: ThemeConfig.characterIconSize,
|
||||
color: ThemeConfig.textColorWhite,
|
||||
);
|
||||
},
|
||||
)
|
||||
: const Icon(
|
||||
Icons.psychology,
|
||||
size: 60,
|
||||
: Icon(
|
||||
isPlayer ? Icons.person : Icons.psychology,
|
||||
size: ThemeConfig.characterIconSize,
|
||||
color: ThemeConfig.textColorWhite,
|
||||
), // 적 이미지
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// const SizedBox(height: 8), // 아이콘과 정보 사이 간격
|
||||
if (!isPlayer && !hideStats)
|
||||
Consumer<BattleProvider>(
|
||||
builder: (context, provider, child) {
|
||||
@@ -166,14 +155,6 @@ class CharacterStatusCard extends StatelessWidget {
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// Text(
|
||||
// "INTENT",
|
||||
// style: TextStyle(
|
||||
// color: ThemeConfig.enemyIntentBorder,
|
||||
// fontSize: 10,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@@ -181,20 +162,18 @@ class CharacterStatusCard extends StatelessWidget {
|
||||
intent.type == EnemyActionType.attack
|
||||
? Icons.flash_on
|
||||
: Icons.shield,
|
||||
color: ThemeConfig.rarityRare, // Yellow
|
||||
size: 16,
|
||||
color: ThemeConfig.rarityRare,
|
||||
size: ThemeConfig.intentIconSize,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Flexible(
|
||||
// Use Flexible to allow text to shrink
|
||||
child: FittedBox(
|
||||
fit:
|
||||
BoxFit.scaleDown, // Shrink text if too long
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Text(
|
||||
intent.description,
|
||||
style: const TextStyle(
|
||||
color: ThemeConfig.textColorWhite,
|
||||
fontSize: 12,
|
||||
fontSize: ThemeConfig.intentFontSize,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user