"/" にファイルをアップロード

This commit is contained in:
2025-12-09 12:52:41 +09:00
commit e4a0f60f3c
5 changed files with 522 additions and 0 deletions

232
home_screen.dart Normal file
View File

@@ -0,0 +1,232 @@
import 'package:flutter/material.dart';
import '../services/formation_generator.dart';
import '../data/formation_positions.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
Map<String, dynamic>? _result;
List<Map<String, String>> _visiblePlayers = [];
bool _isAnimating = false;
// 低確率スタイルモード(デコイラン / ナンバー10 などの確率を下げる)
bool _lowProbabilityMode = false;
Future<void> _generateFormation() async {
setState(() {
_result = null;
_visiblePlayers = [];
_isAnimating = true;
});
// ★ 低確率モードを渡してフォメ+スカッド生成
final newFormation = FormationGenerator.generate(
lowProbMode: _lowProbabilityMode,
);
setState(() {
_result = newFormation;
});
final players = newFormation['positions'] as List<dynamic>;
// 1枚ずつアニメーション的に追加
for (int i = 0; i < players.length; i++) {
await Future.delayed(const Duration(milliseconds: 150));
setState(() {
_visiblePlayers.add(Map<String, String>.from(players[i]));
});
}
setState(() {
_isAnimating = false;
});
}
// ポジションで色分け(表示はしないが色には使う)
Color _getColor(String pos) {
if (pos == 'GK') return Colors.orange;
if (['CB', 'LSB', 'RSB'].contains(pos)) return Colors.blue;
if (['DMF', 'CMF', 'OMF', 'LMF', 'RMF'].contains(pos)) return Colors.green;
if (['CF', 'ST', 'RWG', 'LWG'].contains(pos)) return Colors.red;
return Colors.grey;
}
// カード:表示はプレースタイルのみ
Widget _buildPlayerCard(String pos, String style) {
final color = _getColor(pos);
return Container(
width: 80,
height: 60,
decoration: BoxDecoration(
color: color.withOpacity(0.9),
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.white, width: 1),
),
padding: const EdgeInsets.all(4),
child: Center(
child: Text(
style,
textAlign: TextAlign.center,
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.bold,
),
),
),
);
}
// ピッチにカードを並べる
Widget _buildPitch(String formation, List<Map<String, String>> roles) {
final layout = formationLayouts[formation];
if (layout == null) {
return Center(
child: Text(
'レイアウトが定義されていません: $formation',
style: const TextStyle(color: Colors.white),
),
);
}
return LayoutBuilder(
builder: (context, constraints) {
final width = constraints.maxWidth;
final height = constraints.maxHeight;
const cardW = 80.0;
const cardH = 60.0;
final List<Widget> children = [];
// 背景(ピッチ)
children.add(Container(
width: width,
height: height,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.green.shade800, Colors.green.shade700],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
));
int index = 0;
for (int row = 0; row < layout.length; row++) {
for (int col = 0; col < layout[row].length; col++) {
if (index >= roles.length) break;
final posData = roles[index];
index++;
final xNorm = layout[row][col]['x'] ?? 0.5;
final yNorm = layout[row][col]['y'] ?? 0.5;
final left = width * xNorm - cardW / 2;
final top = height * yNorm - cardH / 2;
children.add(
Positioned(
left: left,
top: top,
child: _buildPlayerCard(
posData['pos'] ?? '',
posData['style'] ?? '',
),
),
);
}
}
return Stack(children: children);
},
);
}
@override
Widget build(BuildContext context) {
final formation = _result?['formation'] as String?;
final positions = _visiblePlayers;
return Scaffold(
backgroundColor: Colors.green[900],
appBar: AppBar(
title: const Text('eFootball スカッドシミュレーター'),
centerTitle: true,
backgroundColor: Colors.green[900],
),
body: Column(
children: [
const SizedBox(height: 8),
// 低確率モードスイッチ
SwitchListTile(
title: const Text(
'低確率スタイルモード(デコイラン等の出現率を下げる)',
style: TextStyle(color: Colors.white),
),
value: _lowProbabilityMode,
onChanged: (v) {
setState(() {
_lowProbabilityMode = v;
});
},
),
const SizedBox(height: 4),
// 抽選ボタン
ElevatedButton.icon(
onPressed: _isAnimating ? null : _generateFormation,
icon: const Icon(Icons.shuffle),
label: const Text('フォーメーション抽選'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: Colors.green[900],
),
),
const SizedBox(height: 8),
// フォーメーション表示
if (formation != null)
Text(
'フォーメーション: $formation',
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
// ピッチ
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: formation == null
? const Center(
child: Text(
'抽選ボタンを押してスカッドを生成',
style: TextStyle(color: Colors.white70, fontSize: 16),
),
)
: _buildPitch(formation, positions),
),
),
],
),
);
}
}