new targets

This commit is contained in:
2025-12-23 16:30:36 +01:00
parent e111f0a99b
commit b727e65d14
32 changed files with 379 additions and 55 deletions
+81 -29
View File
@@ -26,6 +26,7 @@ class TargetViewScreen extends StatefulWidget {
class _TargetViewScreenState extends State<TargetViewScreen> {
int _currentIndex = 0;
List<Offset> _bullets = [];
List<Offset> _scaledBullets = []; // Bullets scaled to display target size
int _totalScore = 0;
Offset? _targetCenter;
Uint8List? _targetImageBytes;
@@ -35,7 +36,10 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
int? _pressedScoreGroup;
late String _targetFilePath;
late String targetAssetPath;
late String _selectedTargetPath; // For display
final double bulletSize = 19;
double _scaleFactorX = 1.0; // Scale factor for X coordinate
double _scaleFactorY = 1.0; // Scale factor for Y coordinate
Color _bulletColor = Colors.blue; // default/fallback bullet color
String _selectedLanguage = 'English';
@@ -72,7 +76,10 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
Future<void> _loadSelectedTarget() async {
final prefs = await SharedPreferences.getInstance();
final selectedTarget = prefs.getString('selectedTarget') ?? 'assets/target.png';
targetAssetPath = selectedTarget;
// Always use default target for bullet positioning
targetAssetPath = 'assets/target.png';
// Store selected target for display
_selectedTargetPath = selectedTarget;
_backgroundColor = _getBackgroundColorForTarget(selectedTarget);
}
@@ -81,37 +88,54 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
switch (targetPath) {
case 'assets/target.png':
return const Color(0xFFFFFFFF); // White
case 'assets/targets/Target1.jpg':
return const Color(0xFFE8ECD5); // Light beige
case 'assets/targets/Target2.jpg':
return const Color(0xFFC1DF87); // Light green
case 'assets/targets/Target3.jpg':
return const Color(0xFFFEFEFE); // Off-white
case 'assets/targets/Target4.jpg':
return const Color(0xFFD42931); // Red
case 'assets/targets/Target5.jpg':
return const Color(0xFF02050A); // Very dark blue/black
case 'assets/targets/Target6.jpg':
return const Color(0xFF000000); // Black
return const Color(0xFFF3E7D1); // Light beige
case 'assets/targets/Target7.jpg':
return const Color(0xFFFFD454); // Bright yellow
case 'assets/targets/Target11.jpg':
case 'assets/targets/Target8.jpg':
return const Color(0xFF1E5E81); // Dark teal blue
case 'assets/targets/Target14.jpg':
case 'assets/targets/Target9.jpg':
return const Color(0xFFFEFEFC); // Off-white
case 'assets/targets/Target15.jpg':
case 'assets/targets/Target10.jpg':
return const Color(0xFF98926E); // Olive green
case 'assets/targets/Target11.jpg':
return const Color(0xFF13132B); // Dark blue
case 'assets/targets/Target12.jpg':
return const Color(0xFFF5F4EF); // Off-white
case 'assets/targets/Target13.jpg':
return const Color(0xFF174AA5); // Blue
case 'assets/targets/Target14.jpg':
return const Color(0xFFFEE05E); // Light yellow
case 'assets/targets/Target15.jpg':
return const Color(0xFFFFFFFF); // White
case 'assets/targets/Target16.jpg':
return const Color(0xFF000000); // Black
case 'assets/targets/Target17.jpg':
return const Color(0xFF13132B); // Dark blue
case 'assets/targets/Target18.jpg':
return const Color(0xFF050608); // Very dark gray
case 'assets/targets/Target19.jpg':
return const Color(0xFFC32534); // Dark red
case 'assets/targets/Target20.jpg':
return const Color(0xFFFCF3EE); // Light beige
case 'assets/targets/Target21.jpg':
return const Color(0xFFDA6868); // Muted red
case 'assets/targets/Target22.jpg':
return const Color(0xFFFDFAF3); // Off-white
case 'assets/targets/Target23.jpg':
return const Color(0xFFFFFFFD); // White
case 'assets/targets/Target24.jpg':
return const Color(0xFFFFC4C6); // Light pink
default:
return Colors.white; // Fallback to white
}
@@ -167,20 +191,33 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
Future<void> _loadJsonAndImage() async {
try {
final byteData = await rootBundle.load(targetAssetPath);
final bytes = byteData.buffer.asUint8List();
_targetImageDecoded = img.decodeImage(bytes);
// Load default target for bullet positioning reference
final defaultByteData = await rootBundle.load(targetAssetPath);
final defaultBytes = defaultByteData.buffer.asUint8List();
img.Image? defaultTargetDecoded = img.decodeImage(defaultBytes);
if (defaultTargetDecoded == null) {
print("Failed to decode default target image.");
return;
}
// Calculate target center from default target (for bullet positioning)
_targetCenter = Offset(
defaultTargetDecoded.width / 2,
defaultTargetDecoded.height / 2 - 1,
);
// Load selected target for display
final displayByteData = await rootBundle.load(_selectedTargetPath);
final displayBytes = displayByteData.buffer.asUint8List();
_targetImageDecoded = img.decodeImage(displayBytes);
if (_targetImageDecoded == null) {
print("Failed to decode image.");
print("Failed to decode display target image.");
return;
}
_targetImageBytes = Uint8List.fromList(img.encodePng(_targetImageDecoded!));
_targetCenter = Offset(
_targetImageDecoded!.width / 2,
_targetImageDecoded!.height / 2 - 1,
);
final currentFile = widget.jsonFiles[_currentIndex];
final jsonString = await currentFile.readAsString();
@@ -210,6 +247,18 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
_targetFilePath = currentFile.path;
// Calculate scale factors based on image dimensions
_scaleFactorX = _targetImageDecoded!.width / defaultTargetDecoded.width;
_scaleFactorY = _targetImageDecoded!.height / defaultTargetDecoded.height;
// Scale bullets to match display target size
_scaledBullets = _bullets.map((bullet) {
return Offset(
bullet.dx * _scaleFactorX,
bullet.dy * _scaleFactorY,
);
}).toList();
_totalScore = _bullets
.map((b) => _scoreForBullet(b, _targetCenter!))
.fold(0, (sum, score) => sum + score);
@@ -386,12 +435,15 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
height: displayHeight,
child: Image.memory(_targetImageBytes!, fit: BoxFit.fill),
),
..._bullets.asMap().entries.map((entry) {
..._scaledBullets.asMap().entries.map((entry) {
final i = entry.key;
final bullet = entry.value;
final dx = bullet.dx * scaleX + offsetX;
final dy = bullet.dy * scaleY + offsetY;
final score = _scoreForBullet(bullet, _targetCenter ?? Offset.zero);
final scaledBullet = entry.value;
// Scaled bullets are already scaled to display target dimensions
final dx = scaledBullet.dx * scaleX + offsetX;
final dy = scaledBullet.dy * scaleY + offsetY;
// Score is calculated using original bullet position and default target center
final originalBullet = _bullets[i];
final score = _scoreForBullet(originalBullet, _targetCenter ?? Offset.zero);
final isHighlighted = widget.isCombinedView
? (_pressedScoreGroup == score)
: (i == _highlightedBulletIndex);