aa
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user