game/lib/widgets/battle/character_status_card.dart

214 lines
8.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../game/models.dart';
import '../../game/enums.dart';
import '../../providers.dart';
import 'battle_animation_widget.dart';
import '../../game/config.dart';
class CharacterStatusCard extends StatelessWidget {
final Character character;
final bool isPlayer;
final bool isTurn;
final GlobalKey<BattleAnimationWidgetState>? animationKey;
final bool hideStats;
const CharacterStatusCard({
super.key,
required this.character,
this.isPlayer = false,
this.isTurn = false,
this.animationKey,
this.hideStats = false,
});
@override
Widget build(BuildContext context) {
return Column(
children: [
AnimatedOpacity(
opacity: hideStats ? 0.0 : 1.0,
duration: AnimationConfig.fadeDuration,
child: Column(
children: [
FittedBox(
fit: BoxFit.scaleDown,
child: Text(
"Armor: ${character.armor}",
style: const TextStyle(color: ThemeConfig.textColorWhite),
),
),
FittedBox(
fit: BoxFit.scaleDown,
child: Text(
"${character.name}: HP ${character.hp}/${character.totalMaxHp}",
style: TextStyle(
color: character.isDead
? ThemeConfig.statHpEnemyColor
: ThemeConfig.textColorWhite,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(
width: 100,
child: LinearProgressIndicator(
value: character.totalMaxHp > 0
? character.hp / character.totalMaxHp
: 0,
color: !isPlayer
? ThemeConfig.statHpEnemyColor
: ThemeConfig.statHpPlayerColor,
backgroundColor: ThemeConfig.textColorGrey,
),
),
if (character.statusEffects.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Wrap(
spacing: 4.0,
children: character.statusEffects.map((effect) {
final isBuff = effect.type == StatusEffectType.attackUp;
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 6,
vertical: 2,
),
decoration: BoxDecoration(
color: isBuff
? ThemeConfig.effectBuffBg
: ThemeConfig.effectDebuffBg,
borderRadius: BorderRadius.circular(4),
),
child: Text(
"${effect.type.name.toUpperCase()} (${effect.duration})",
style: const TextStyle(
color: ThemeConfig.effectText,
fontSize: 10,
fontWeight: FontWeight.bold,
),
),
);
}).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), // 아이콘과 정보 사이 간격
// 캐릭터 아이콘/이미지 영역 추가
BattleAnimationWidget(
key: animationKey,
child: Container(
width: isPlayer ? 100 : 200, // 플레이어 100, 적 200
height: isPlayer ? 100 : 200, // 플레이어 100, 적 200
decoration: BoxDecoration(
color: isPlayer ? Colors.lightBlue : null,
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: isPlayer
? const Icon(
Icons.person,
size: 60,
color: ThemeConfig.textColorWhite,
) // 플레이어 아이콘
: (character.image != null && character.image!.isNotEmpty)
? Image.asset(
character.image!,
width: 200,
height: 200,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
return const Icon(
Icons.psychology,
size: 60,
color: ThemeConfig.textColorWhite,
);
},
)
: const Icon(
Icons.psychology,
size: 60,
color: ThemeConfig.textColorWhite,
), // 적 이미지
),
),
),
// const SizedBox(height: 8), // 아이콘과 정보 사이 간격
if (!isPlayer && !hideStats)
Consumer<BattleProvider>(
builder: (context, provider, child) {
if (provider.currentEnemyIntent != null && !character.isDead) {
final intent = provider.currentEnemyIntent!;
return Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: ThemeConfig.enemyIntentBg,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: ThemeConfig.enemyIntentBorder),
),
child: Column(
children: [
// Text(
// "INTENT",
// style: TextStyle(
// color: ThemeConfig.enemyIntentBorder,
// fontSize: 10,
// fontWeight: FontWeight.bold,
// ),
// ),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
intent.type == EnemyActionType.attack
? Icons.flash_on
: Icons.shield,
color: ThemeConfig.rarityRare, // Yellow
size: 16,
),
const SizedBox(width: 4),
Flexible(
// Use Flexible to allow text to shrink
child: FittedBox(
fit:
BoxFit.scaleDown, // Shrink text if too long
child: Text(
intent.description,
style: const TextStyle(
color: ThemeConfig.textColorWhite,
fontSize: 12,
),
),
),
),
],
),
],
),
),
);
}
return const SizedBox.shrink();
},
),
],
);
}
}