This commit is contained in:
horoli 2026-01-26 00:53:04 +09:00
parent 14c99305c4
commit 8297ce980f
8 changed files with 297 additions and 52 deletions

View File

@ -5,8 +5,10 @@
"baseHp": 30, "baseHp": 30,
"baseAtk": 6, "baseAtk": 6,
"baseDefense": 0, "baseDefense": 0,
"image": "assets/images/enemies/scrawny_gladiator.png", "image": "assets/images/enemies/Orc.png",
"equipment": ["pot_lid"], "equipment": [
"pot_lid"
],
"tier": 1 "tier": 1
}, },
{ {
@ -25,7 +27,9 @@
"baseAtk": 4, "baseAtk": 4,
"baseDefense": 1, "baseDefense": 1,
"image": "assets/images/enemies/clumsy_gladiator.png", "image": "assets/images/enemies/clumsy_gladiator.png",
"equipment": ["simple_rags"], "equipment": [
"simple_rags"
],
"tier": 1 "tier": 1
}, },
{ {
@ -34,7 +38,9 @@
"baseAtk": 7, "baseAtk": 7,
"baseDefense": 1, "baseDefense": 1,
"image": "assets/images/enemies/desperate_gladiator.png", "image": "assets/images/enemies/desperate_gladiator.png",
"equipment": ["gladius"], "equipment": [
"gladius"
],
"tier": 1 "tier": 1
}, },
{ {
@ -43,7 +49,9 @@
"baseAtk": 6, "baseAtk": 6,
"baseDefense": 3, "baseDefense": 3,
"image": "assets/images/enemies/untrained_gladiator.png", "image": "assets/images/enemies/untrained_gladiator.png",
"equipment": ["wooden_buckler"], "equipment": [
"wooden_buckler"
],
"tier": 1 "tier": 1
}, },
{ {
@ -61,7 +69,9 @@
"baseAtk": 5, "baseAtk": 5,
"baseDefense": 5, "baseDefense": 5,
"image": "assets/images/enemies/chained_gladiator.png", "image": "assets/images/enemies/chained_gladiator.png",
"equipment": ["flail"], "equipment": [
"flail"
],
"tier": 1 "tier": 1
}, },
{ {
@ -70,7 +80,9 @@
"baseAtk": 8, "baseAtk": 8,
"baseDefense": 3, "baseDefense": 3,
"image": "assets/images/enemies/retiarius.png", "image": "assets/images/enemies/retiarius.png",
"equipment": ["trident"], "equipment": [
"trident"
],
"tier": 1 "tier": 1
}, },
{ {
@ -79,7 +91,9 @@
"baseAtk": 15, "baseAtk": 15,
"baseDefense": 4, "baseDefense": 4,
"image": "assets/images/enemies/one_eyed_gladiator.png", "image": "assets/images/enemies/one_eyed_gladiator.png",
"equipment": ["scimitar"], "equipment": [
"scimitar"
],
"tier": 2 "tier": 2
}, },
{ {
@ -88,7 +102,9 @@
"baseAtk": 18, "baseAtk": 18,
"baseDefense": 5, "baseDefense": 5,
"image": "assets/images/enemies/brutal_gladiator.png", "image": "assets/images/enemies/brutal_gladiator.png",
"equipment": ["war_axe"], "equipment": [
"war_axe"
],
"tier": 2 "tier": 2
}, },
{ {
@ -97,7 +113,10 @@
"baseAtk": 15, "baseAtk": 15,
"baseDefense": 10, "baseDefense": 10,
"image": "assets/images/enemies/veteran_gladiator.png", "image": "assets/images/enemies/veteran_gladiator.png",
"equipment": ["gladius", "leather_vest"], "equipment": [
"gladius",
"leather_vest"
],
"tier": 2 "tier": 2
}, },
{ {
@ -107,7 +126,9 @@
"baseDefense": 7, "baseDefense": 7,
"baseDodge": 15, "baseDodge": 15,
"image": "assets/images/enemies/swift_gladiator.png", "image": "assets/images/enemies/swift_gladiator.png",
"equipment": ["scimitar"], "equipment": [
"scimitar"
],
"tier": 2 "tier": 2
}, },
{ {
@ -117,7 +138,10 @@
"baseDefense": 8, "baseDefense": 8,
"luck": 10, "luck": 10,
"image": "assets/images/enemies/cunning_gladiator.png", "image": "assets/images/enemies/cunning_gladiator.png",
"equipment": ["flail", "tarnished_ring"], "equipment": [
"flail",
"tarnished_ring"
],
"tier": 2 "tier": 2
}, },
{ {
@ -126,7 +150,11 @@
"baseAtk": 15, "baseAtk": 15,
"baseDefense": 12, "baseDefense": 12,
"image": "assets/images/enemies/hoplomachus.png", "image": "assets/images/enemies/hoplomachus.png",
"equipment": ["trident", "kite_shield", "chainmail"], "equipment": [
"trident",
"kite_shield",
"chainmail"
],
"tier": 2 "tier": 2
}, },
{ {
@ -136,7 +164,9 @@
"baseDefense": 5, "baseDefense": 5,
"baseDodge": -5, "baseDodge": -5,
"image": "assets/images/enemies/drunken_gladiator.png", "image": "assets/images/enemies/drunken_gladiator.png",
"equipment": ["war_axe"], "equipment": [
"war_axe"
],
"tier": 2 "tier": 2
}, },
{ {
@ -145,7 +175,10 @@
"baseAtk": 10, "baseAtk": 10,
"baseDefense": 12, "baseDefense": 12,
"image": "assets/images/enemies/the_wall.png", "image": "assets/images/enemies/the_wall.png",
"equipment": ["tower_shield", "chainmail"], "equipment": [
"tower_shield",
"chainmail"
],
"tier": 2 "tier": 2
}, },
{ {
@ -154,7 +187,10 @@
"baseAtk": 25, "baseAtk": 25,
"baseDefense": 12, "baseDefense": 12,
"image": "assets/images/enemies/champion_gannicus.png", "image": "assets/images/enemies/champion_gannicus.png",
"equipment": ["steel_greatsword", "steel_plate"], "equipment": [
"steel_greatsword",
"steel_plate"
],
"tier": 3 "tier": 3
}, },
{ {
@ -163,7 +199,9 @@
"baseAtk": 30, "baseAtk": 30,
"baseDefense": 10, "baseDefense": 10,
"image": "assets/images/enemies/the_giant.png", "image": "assets/images/enemies/the_giant.png",
"equipment": ["war_hammer"], "equipment": [
"war_hammer"
],
"tier": 3 "tier": 3
}, },
{ {
@ -172,7 +210,9 @@
"baseAtk": 25, "baseAtk": 25,
"baseDefense": 14, "baseDefense": 14,
"image": "assets/images/enemies/bloody_flamma.png", "image": "assets/images/enemies/bloody_flamma.png",
"equipment": ["barbed_net"], "equipment": [
"barbed_net"
],
"tier": 3 "tier": 3
}, },
{ {
@ -181,7 +221,10 @@
"baseAtk": 24, "baseAtk": 24,
"baseDefense": 20, "baseDefense": 20,
"image": "assets/images/enemies/legendary_oenomaus.png", "image": "assets/images/enemies/legendary_oenomaus.png",
"equipment": ["scimitar", "steel_shield"], "equipment": [
"scimitar",
"steel_shield"
],
"tier": 3 "tier": 3
}, },
{ {
@ -191,7 +234,9 @@
"baseDefense": 12, "baseDefense": 12,
"baseDodge": 30, "baseDodge": 30,
"image": "assets/images/enemies/the_unseen.png", "image": "assets/images/enemies/the_unseen.png",
"equipment": ["hooked_spear"], "equipment": [
"hooked_spear"
],
"tier": 3 "tier": 3
}, },
{ {
@ -200,7 +245,9 @@
"baseAtk": 35, "baseAtk": 35,
"baseDefense": 15, "baseDefense": 15,
"image": "assets/images/enemies/executioner.png", "image": "assets/images/enemies/executioner.png",
"equipment": ["executioners_axe"], "equipment": [
"executioners_axe"
],
"tier": 3 "tier": 3
}, },
{ {
@ -209,7 +256,9 @@
"baseAtk": 35, "baseAtk": 35,
"baseDefense": 16, "baseDefense": 16,
"image": "assets/images/enemies/vengeful_spartacus.png", "image": "assets/images/enemies/vengeful_spartacus.png",
"equipment": ["gladius"], "equipment": [
"gladius"
],
"tier": 3 "tier": 3
}, },
{ {
@ -218,7 +267,11 @@
"baseAtk": 28, "baseAtk": 28,
"baseDefense": 25, "baseDefense": 25,
"image": "assets/images/enemies/praetorian_guard.png", "image": "assets/images/enemies/praetorian_guard.png",
"equipment": ["steel_greatsword", "steel_plate", "tower_shield"], "equipment": [
"steel_greatsword",
"steel_plate",
"tower_shield"
],
"tier": 3 "tier": 3
} }
], ],
@ -229,7 +282,10 @@
"baseAtk": 14, "baseAtk": 14,
"baseDefense": 5, "baseDefense": 5,
"image": "assets/images/enemies/crixus_the_gaul.png", "image": "assets/images/enemies/crixus_the_gaul.png",
"equipment": ["long_sword", "kite_shield"], "equipment": [
"long_sword",
"kite_shield"
],
"tier": 1 "tier": 1
}, },
{ {
@ -238,7 +294,9 @@
"baseAtk": 28, "baseAtk": 28,
"baseDefense": 8, "baseDefense": 8,
"image": "assets/images/enemies/theokoles.png", "image": "assets/images/enemies/theokoles.png",
"equipment": ["war_axe"], "equipment": [
"war_axe"
],
"tier": 1 "tier": 1
}, },
{ {
@ -247,7 +305,9 @@
"baseAtk": 22, "baseAtk": 22,
"baseDefense": 10, "baseDefense": 10,
"image": "assets/images/enemies/isidorus_the_butcher.png", "image": "assets/images/enemies/isidorus_the_butcher.png",
"equipment": ["trident"], "equipment": [
"trident"
],
"tier": 1 "tier": 1
}, },
{ {
@ -257,7 +317,11 @@
"baseDefense": 10, "baseDefense": 10,
"luck": 15, "luck": 15,
"image": "assets/images/enemies/vitallion_the_lion.png", "image": "assets/images/enemies/vitallion_the_lion.png",
"equipment": ["war_hammer", "chainmail", "engraved_amulet"], "equipment": [
"war_hammer",
"chainmail",
"engraved_amulet"
],
"tier": 2 "tier": 2
}, },
{ {
@ -267,7 +331,9 @@
"baseDefense": 15, "baseDefense": 15,
"baseDodge": 15, "baseDodge": 15,
"image": "assets/images/enemies/arcas_the_serpent.png", "image": "assets/images/enemies/arcas_the_serpent.png",
"equipment": ["hooked_spear"], "equipment": [
"hooked_spear"
],
"tier": 2 "tier": 2
}, },
{ {
@ -276,7 +342,10 @@
"baseAtk": 30, "baseAtk": 30,
"baseDefense": 20, "baseDefense": 20,
"image": "assets/images/enemies/verus_the_undefeated.png", "image": "assets/images/enemies/verus_the_undefeated.png",
"equipment": ["steel_greatsword", "steel_shield"], "equipment": [
"steel_greatsword",
"steel_shield"
],
"tier": 2 "tier": 2
}, },
{ {
@ -285,7 +354,11 @@
"baseAtk": 38, "baseAtk": 38,
"baseDefense": 30, "baseDefense": 30,
"image": "assets/images/enemies/magistratus_maxentius.png", "image": "assets/images/enemies/magistratus_maxentius.png",
"equipment": ["executioners_axe", "steel_plate", "champions_badge"], "equipment": [
"executioners_axe",
"steel_plate",
"champions_badge"
],
"tier": 3 "tier": 3
}, },
{ {
@ -295,7 +368,9 @@
"baseDefense": 15, "baseDefense": 15,
"baseDodge": 20, "baseDodge": 20,
"image": "assets/images/enemies/aurelia_crimson_blade.png", "image": "assets/images/enemies/aurelia_crimson_blade.png",
"equipment": ["scimitar"], "equipment": [
"scimitar"
],
"tier": 3 "tier": 3
}, },
{ {
@ -304,7 +379,9 @@
"baseAtk": 40, "baseAtk": 40,
"baseDefense": 18, "baseDefense": 18,
"image": "assets/images/enemies/chimera.png", "image": "assets/images/enemies/chimera.png",
"equipment": ["sunderer_axe"], "equipment": [
"sunderer_axe"
],
"tier": 3 "tier": 3
} }
] ]

View File

@ -7,7 +7,7 @@
"baseAtk": 5, "baseAtk": 5,
"baseDefense": 5, "baseDefense": 5,
"baseDodge": 2, "baseDodge": 2,
"image": "assets/images/character/warrior.png" "image": "assets/images/character/Soldier.png"
}, },
{ {
"id": "rogue", "id": "rogue",

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -6,6 +6,7 @@ import '../widgets.dart';
import '../game/save_manager.dart'; import '../game/save_manager.dart';
import '../providers.dart'; import '../providers.dart';
import '../game/config.dart'; import '../game/config.dart';
import '../widgets/test/sprite_animation_widget.dart';
class MainMenuScreen extends StatefulWidget { class MainMenuScreen extends StatefulWidget {
const MainMenuScreen({super.key}); const MainMenuScreen({super.key});
@ -69,6 +70,19 @@ class _MainMenuScreenState extends State<MainMenuScreen> {
: Column( : Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ 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( const Icon(
Icons.gavel, Icons.gavel,
size: 100, size: 100,

View File

@ -5,6 +5,7 @@ import '../../game/enums.dart';
import '../../providers.dart'; import '../../providers.dart';
import 'battle_animation_widget.dart'; import 'battle_animation_widget.dart';
import '../../game/config.dart'; import '../../game/config.dart';
import '../test/sprite_animation_widget.dart'; // Temporary for testing
class CharacterStatusCard extends StatelessWidget { class CharacterStatusCard extends StatelessWidget {
final Character character; final Character character;
@ -107,29 +108,27 @@ class CharacterStatusCard extends StatelessWidget {
height: isPlayer height: isPlayer
? ThemeConfig.playerImageSize ? ThemeConfig.playerImageSize
: ThemeConfig.enemyImageSize, : ThemeConfig.enemyImageSize,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration( decoration: BoxDecoration(
// color: isPlayer ? ThemeConfig.playerImageBgColor : null, // color: isPlayer ? ThemeConfig.playerImageBgColor : null,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
child: Center( child: Center(
child: (overrideImage != null || child:
(overrideImage != null ||
(character.image != null && character.image!.isNotEmpty)) (character.image != null && character.image!.isNotEmpty))
? Image.asset( ? OverflowBox(
overrideImage ?? character.image!, minWidth: 0,
width: isPlayer maxWidth: double.infinity,
? ThemeConfig.playerImageSize minHeight: 0,
: ThemeConfig.enemyImageSize, maxHeight: double.infinity,
height: isPlayer alignment: Alignment.center,
? ThemeConfig.playerImageSize child: SpriteAnimationWidget(
: ThemeConfig.enemyImageSize, // assetPath: 'assets/images/character/Soldier.png',
fit: BoxFit.contain, assetPath: overrideImage ?? character.image!,
errorBuilder: (context, error, stackTrace) { scale: 5.0, // Zoomed in (300x300 in 200x200 box)
return const Icon( frameCount: 6,
Icons.error_outline, ),
size: ThemeConfig.characterIconSize,
color: ThemeConfig.textColorWhite,
);
},
) )
: Icon( : Icon(
isPlayer ? Icons.person : Icons.psychology, isPlayer ? Icons.person : Icons.psychology,

View File

@ -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<SpriteAnimationWidget> createState() => _SpriteAnimationWidgetState();
}
class _SpriteAnimationWidgetState extends State<SpriteAnimationWidget>
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<void> _loadImage() async {
try {
final ByteData data = await rootBundle.load(widget.assetPath);
final List<int> bytes = data.buffer.asUint8List();
final Completer<ui.Image> 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;
}
}