diff --git a/assets/data/enemies.json b/assets/data/enemies.json index 7027191..2238839 100644 --- a/assets/data/enemies.json +++ b/assets/data/enemies.json @@ -5,8 +5,10 @@ "baseHp": 30, "baseAtk": 6, "baseDefense": 0, - "image": "assets/images/enemies/scrawny_gladiator.png", - "equipment": ["pot_lid"], + "image": "assets/images/enemies/Orc.png", + "equipment": [ + "pot_lid" + ], "tier": 1 }, { @@ -25,7 +27,9 @@ "baseAtk": 4, "baseDefense": 1, "image": "assets/images/enemies/clumsy_gladiator.png", - "equipment": ["simple_rags"], + "equipment": [ + "simple_rags" + ], "tier": 1 }, { @@ -34,7 +38,9 @@ "baseAtk": 7, "baseDefense": 1, "image": "assets/images/enemies/desperate_gladiator.png", - "equipment": ["gladius"], + "equipment": [ + "gladius" + ], "tier": 1 }, { @@ -43,7 +49,9 @@ "baseAtk": 6, "baseDefense": 3, "image": "assets/images/enemies/untrained_gladiator.png", - "equipment": ["wooden_buckler"], + "equipment": [ + "wooden_buckler" + ], "tier": 1 }, { @@ -61,7 +69,9 @@ "baseAtk": 5, "baseDefense": 5, "image": "assets/images/enemies/chained_gladiator.png", - "equipment": ["flail"], + "equipment": [ + "flail" + ], "tier": 1 }, { @@ -70,7 +80,9 @@ "baseAtk": 8, "baseDefense": 3, "image": "assets/images/enemies/retiarius.png", - "equipment": ["trident"], + "equipment": [ + "trident" + ], "tier": 1 }, { @@ -79,7 +91,9 @@ "baseAtk": 15, "baseDefense": 4, "image": "assets/images/enemies/one_eyed_gladiator.png", - "equipment": ["scimitar"], + "equipment": [ + "scimitar" + ], "tier": 2 }, { @@ -88,7 +102,9 @@ "baseAtk": 18, "baseDefense": 5, "image": "assets/images/enemies/brutal_gladiator.png", - "equipment": ["war_axe"], + "equipment": [ + "war_axe" + ], "tier": 2 }, { @@ -97,7 +113,10 @@ "baseAtk": 15, "baseDefense": 10, "image": "assets/images/enemies/veteran_gladiator.png", - "equipment": ["gladius", "leather_vest"], + "equipment": [ + "gladius", + "leather_vest" + ], "tier": 2 }, { @@ -107,7 +126,9 @@ "baseDefense": 7, "baseDodge": 15, "image": "assets/images/enemies/swift_gladiator.png", - "equipment": ["scimitar"], + "equipment": [ + "scimitar" + ], "tier": 2 }, { @@ -117,7 +138,10 @@ "baseDefense": 8, "luck": 10, "image": "assets/images/enemies/cunning_gladiator.png", - "equipment": ["flail", "tarnished_ring"], + "equipment": [ + "flail", + "tarnished_ring" + ], "tier": 2 }, { @@ -126,7 +150,11 @@ "baseAtk": 15, "baseDefense": 12, "image": "assets/images/enemies/hoplomachus.png", - "equipment": ["trident", "kite_shield", "chainmail"], + "equipment": [ + "trident", + "kite_shield", + "chainmail" + ], "tier": 2 }, { @@ -136,7 +164,9 @@ "baseDefense": 5, "baseDodge": -5, "image": "assets/images/enemies/drunken_gladiator.png", - "equipment": ["war_axe"], + "equipment": [ + "war_axe" + ], "tier": 2 }, { @@ -145,7 +175,10 @@ "baseAtk": 10, "baseDefense": 12, "image": "assets/images/enemies/the_wall.png", - "equipment": ["tower_shield", "chainmail"], + "equipment": [ + "tower_shield", + "chainmail" + ], "tier": 2 }, { @@ -154,7 +187,10 @@ "baseAtk": 25, "baseDefense": 12, "image": "assets/images/enemies/champion_gannicus.png", - "equipment": ["steel_greatsword", "steel_plate"], + "equipment": [ + "steel_greatsword", + "steel_plate" + ], "tier": 3 }, { @@ -163,7 +199,9 @@ "baseAtk": 30, "baseDefense": 10, "image": "assets/images/enemies/the_giant.png", - "equipment": ["war_hammer"], + "equipment": [ + "war_hammer" + ], "tier": 3 }, { @@ -172,7 +210,9 @@ "baseAtk": 25, "baseDefense": 14, "image": "assets/images/enemies/bloody_flamma.png", - "equipment": ["barbed_net"], + "equipment": [ + "barbed_net" + ], "tier": 3 }, { @@ -181,7 +221,10 @@ "baseAtk": 24, "baseDefense": 20, "image": "assets/images/enemies/legendary_oenomaus.png", - "equipment": ["scimitar", "steel_shield"], + "equipment": [ + "scimitar", + "steel_shield" + ], "tier": 3 }, { @@ -191,7 +234,9 @@ "baseDefense": 12, "baseDodge": 30, "image": "assets/images/enemies/the_unseen.png", - "equipment": ["hooked_spear"], + "equipment": [ + "hooked_spear" + ], "tier": 3 }, { @@ -200,7 +245,9 @@ "baseAtk": 35, "baseDefense": 15, "image": "assets/images/enemies/executioner.png", - "equipment": ["executioners_axe"], + "equipment": [ + "executioners_axe" + ], "tier": 3 }, { @@ -209,7 +256,9 @@ "baseAtk": 35, "baseDefense": 16, "image": "assets/images/enemies/vengeful_spartacus.png", - "equipment": ["gladius"], + "equipment": [ + "gladius" + ], "tier": 3 }, { @@ -218,7 +267,11 @@ "baseAtk": 28, "baseDefense": 25, "image": "assets/images/enemies/praetorian_guard.png", - "equipment": ["steel_greatsword", "steel_plate", "tower_shield"], + "equipment": [ + "steel_greatsword", + "steel_plate", + "tower_shield" + ], "tier": 3 } ], @@ -229,7 +282,10 @@ "baseAtk": 14, "baseDefense": 5, "image": "assets/images/enemies/crixus_the_gaul.png", - "equipment": ["long_sword", "kite_shield"], + "equipment": [ + "long_sword", + "kite_shield" + ], "tier": 1 }, { @@ -238,7 +294,9 @@ "baseAtk": 28, "baseDefense": 8, "image": "assets/images/enemies/theokoles.png", - "equipment": ["war_axe"], + "equipment": [ + "war_axe" + ], "tier": 1 }, { @@ -247,7 +305,9 @@ "baseAtk": 22, "baseDefense": 10, "image": "assets/images/enemies/isidorus_the_butcher.png", - "equipment": ["trident"], + "equipment": [ + "trident" + ], "tier": 1 }, { @@ -257,7 +317,11 @@ "baseDefense": 10, "luck": 15, "image": "assets/images/enemies/vitallion_the_lion.png", - "equipment": ["war_hammer", "chainmail", "engraved_amulet"], + "equipment": [ + "war_hammer", + "chainmail", + "engraved_amulet" + ], "tier": 2 }, { @@ -267,7 +331,9 @@ "baseDefense": 15, "baseDodge": 15, "image": "assets/images/enemies/arcas_the_serpent.png", - "equipment": ["hooked_spear"], + "equipment": [ + "hooked_spear" + ], "tier": 2 }, { @@ -276,7 +342,10 @@ "baseAtk": 30, "baseDefense": 20, "image": "assets/images/enemies/verus_the_undefeated.png", - "equipment": ["steel_greatsword", "steel_shield"], + "equipment": [ + "steel_greatsword", + "steel_shield" + ], "tier": 2 }, { @@ -285,7 +354,11 @@ "baseAtk": 38, "baseDefense": 30, "image": "assets/images/enemies/magistratus_maxentius.png", - "equipment": ["executioners_axe", "steel_plate", "champions_badge"], + "equipment": [ + "executioners_axe", + "steel_plate", + "champions_badge" + ], "tier": 3 }, { @@ -295,7 +368,9 @@ "baseDefense": 15, "baseDodge": 20, "image": "assets/images/enemies/aurelia_crimson_blade.png", - "equipment": ["scimitar"], + "equipment": [ + "scimitar" + ], "tier": 3 }, { @@ -304,8 +379,10 @@ "baseAtk": 40, "baseDefense": 18, "image": "assets/images/enemies/chimera.png", - "equipment": ["sunderer_axe"], + "equipment": [ + "sunderer_axe" + ], "tier": 3 } ] -} +} \ No newline at end of file diff --git a/assets/data/players.json b/assets/data/players.json index 28c0d0e..2167f13 100644 --- a/assets/data/players.json +++ b/assets/data/players.json @@ -7,7 +7,7 @@ "baseAtk": 5, "baseDefense": 5, "baseDodge": 2, - "image": "assets/images/character/warrior.png" + "image": "assets/images/character/Soldier.png" }, { "id": "rogue", @@ -19,4 +19,4 @@ "baseDodge": 15, "image": "assets/images/character/rogue.png" } -] +] \ No newline at end of file diff --git a/assets/images/character/Soldier-Attack01.png b/assets/images/character/Soldier-Attack01.png new file mode 100644 index 0000000..a39e058 Binary files /dev/null and b/assets/images/character/Soldier-Attack01.png differ diff --git a/assets/images/character/Soldier.png b/assets/images/character/Soldier.png new file mode 100644 index 0000000..f006107 Binary files /dev/null and b/assets/images/character/Soldier.png differ diff --git a/assets/images/enemies/Orc.png b/assets/images/enemies/Orc.png new file mode 100644 index 0000000..4ef7b97 Binary files /dev/null and b/assets/images/enemies/Orc.png differ diff --git a/lib/screens/main_menu_screen.dart b/lib/screens/main_menu_screen.dart index cfc7b7a..fb4444f 100644 --- a/lib/screens/main_menu_screen.dart +++ b/lib/screens/main_menu_screen.dart @@ -6,6 +6,7 @@ import '../widgets.dart'; import '../game/save_manager.dart'; import '../providers.dart'; import '../game/config.dart'; +import '../widgets/test/sprite_animation_widget.dart'; class MainMenuScreen extends StatefulWidget { const MainMenuScreen({super.key}); @@ -69,6 +70,19 @@ class _MainMenuScreenState extends State { : Column( mainAxisAlignment: MainAxisAlignment.center, children: [ + // const SpriteAnimationWidget( + // assetPath: 'assets/images/character/Soldier.png', + // scale: 5.0, // Make it bigger for visibility + // frameCount: + // 6, // Explicitly limit to 6 frames to avoid flickering from empty frames + // ), + // const SpriteAnimationWidget( + // assetPath: 'assets/images/character/Soldier-Attack01.png', + // scale: 5.0, // Make it bigger for visibility + // frameCount: + // 6, // Explicitly limit to 6 frames to avoid flickering from empty frames + // ), + const SizedBox(height: 20), const Icon( Icons.gavel, size: 100, diff --git a/lib/widgets/battle/character_status_card.dart b/lib/widgets/battle/character_status_card.dart index c2ac49f..d5ab7cc 100644 --- a/lib/widgets/battle/character_status_card.dart +++ b/lib/widgets/battle/character_status_card.dart @@ -5,6 +5,7 @@ import '../../game/enums.dart'; import '../../providers.dart'; import 'battle_animation_widget.dart'; import '../../game/config.dart'; +import '../test/sprite_animation_widget.dart'; // Temporary for testing class CharacterStatusCard extends StatelessWidget { final Character character; @@ -107,29 +108,27 @@ class CharacterStatusCard extends StatelessWidget { height: isPlayer ? ThemeConfig.playerImageSize : ThemeConfig.enemyImageSize, + clipBehavior: Clip.antiAlias, decoration: BoxDecoration( // color: isPlayer ? ThemeConfig.playerImageBgColor : null, borderRadius: BorderRadius.circular(8), ), child: Center( - child: (overrideImage != null || + child: + (overrideImage != null || (character.image != null && character.image!.isNotEmpty)) - ? Image.asset( - overrideImage ?? character.image!, - width: isPlayer - ? ThemeConfig.playerImageSize - : ThemeConfig.enemyImageSize, - height: isPlayer - ? ThemeConfig.playerImageSize - : ThemeConfig.enemyImageSize, - fit: BoxFit.contain, - errorBuilder: (context, error, stackTrace) { - return const Icon( - Icons.error_outline, - size: ThemeConfig.characterIconSize, - color: ThemeConfig.textColorWhite, - ); - }, + ? OverflowBox( + minWidth: 0, + maxWidth: double.infinity, + minHeight: 0, + maxHeight: double.infinity, + alignment: Alignment.center, + child: SpriteAnimationWidget( + // assetPath: 'assets/images/character/Soldier.png', + assetPath: overrideImage ?? character.image!, + scale: 5.0, // Zoomed in (300x300 in 200x200 box) + frameCount: 6, + ), ) : Icon( isPlayer ? Icons.person : Icons.psychology, diff --git a/lib/widgets/test/sprite_animation_widget.dart b/lib/widgets/test/sprite_animation_widget.dart new file mode 100644 index 0000000..eb199ca --- /dev/null +++ b/lib/widgets/test/sprite_animation_widget.dart @@ -0,0 +1,155 @@ +import 'dart:async'; +import 'dart:ui' as ui; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class SpriteAnimationWidget extends StatefulWidget { + final String assetPath; + final double tileWidth; + final double tileHeight; + final int frameCount; + final double scale; + + const SpriteAnimationWidget({ + super.key, + required this.assetPath, + this.tileWidth = 100.0, + this.tileHeight = 100.0, + this.frameCount = + 6, // Default guess, will adjust logic to use actual image width if possible + this.scale = 1.0, + }); + + @override + State createState() => _SpriteAnimationWidgetState(); +} + +class _SpriteAnimationWidgetState extends State + with SingleTickerProviderStateMixin { + ui.Image? _image; + late AnimationController _controller; + bool _isLoading = true; + int _calculatedFrameCount = 6; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 600), // 100ms per frame approx + ); + _loadImage(); + } + + Future _loadImage() async { + try { + final ByteData data = await rootBundle.load(widget.assetPath); + final List bytes = data.buffer.asUint8List(); + final Completer completer = Completer(); + ui.decodeImageFromList(Uint8List.fromList(bytes), (ui.Image img) { + completer.complete(img); + }); + final image = await completer.future; + + if (mounted) { + setState(() { + _image = image; + _isLoading = false; + // Use provided frameCount, but clamp to available frames in image + int maxFrames = (image.width / widget.tileWidth).floor(); + _calculatedFrameCount = widget.frameCount > maxFrames + ? maxFrames + : widget.frameCount; + + // Adjust duration based on frame count + _controller.duration = Duration( + milliseconds: _calculatedFrameCount * 100, + ); + _controller.repeat(); + }); + } + } catch (e) { + debugPrint('Failed to load sprite image: $e'); + } + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (_isLoading || _image == null) { + return SizedBox( + width: widget.tileWidth * widget.scale, + height: widget.tileHeight * widget.scale, + child: const Center(child: CircularProgressIndicator()), + ); + } + + return AnimatedBuilder( + animation: _controller, + builder: (context, child) { + return CustomPaint( + size: Size( + widget.tileWidth * widget.scale, + widget.tileHeight * widget.scale, + ), + painter: SpriteSheetPainter( + image: _image!, + currentFrame: + (_controller.value * _calculatedFrameCount).floor() % + _calculatedFrameCount, + tileWidth: widget.tileWidth, + tileHeight: widget.tileHeight, + scale: widget.scale, + ), + ); + }, + ); + } +} + +class SpriteSheetPainter extends CustomPainter { + final ui.Image image; + final int currentFrame; + final double tileWidth; + final double tileHeight; + final double scale; + + SpriteSheetPainter({ + required this.image, + required this.currentFrame, + required this.tileWidth, + required this.tileHeight, + required this.scale, + }); + + @override + void paint(Canvas canvas, Size size) { + // Correct src rect calculation + // Assuming horizontal strip for the animation row. + // Ideally we would want to select which 'row' (Y) to animate, but for now assuming row 0. + // If the image is a single row, srcY is 0. + final double srcX = currentFrame * tileWidth; + final double srcY = 0.0; // Default to first row + + final Rect src = Rect.fromLTWH(srcX, srcY, tileWidth, tileHeight); + final Rect dst = Rect.fromLTWH(0, 0, tileWidth * scale, tileHeight * scale); + + canvas.drawImageRect( + image, + src, + dst, + Paint()..filterQuality = FilterQuality.none, + ); + } + + @override + bool shouldRepaint(covariant SpriteSheetPainter oldDelegate) { + return oldDelegate.currentFrame != currentFrame || + oldDelegate.image != image; + } +}