feat: endless mode UI - game over card, best score, HUD

This commit is contained in:
2026-06-12 07:06:30 +09:00
parent c5e9029cad
commit fea8336391
8 changed files with 110 additions and 8 deletions
+41 -4
View File
@@ -41,6 +41,7 @@ class _GameScreenState extends ConsumerState<GameScreen>
);
bool _tutorialStartChecked = false;
bool _endlessNewBest = false;
int? _dragIndex;
Offset? _dragGlobal;
@@ -155,9 +156,11 @@ class _GameScreenState extends ConsumerState<GameScreen>
if (next.phase == GamePhase.won) {
audio.play(Sfx.win);
// recordResult keeps the best run, so re-entry is harmless.
ref
.read(seasonFlowProvider.notifier)
.recordWin(stars: next.starsEarned, score: next.score);
if (!next.endless) {
ref
.read(seasonFlowProvider.notifier)
.recordWin(stars: next.starsEarned, score: next.score);
}
final stackBox =
_stackKey.currentContext?.findRenderObject() as RenderBox?;
if (stackBox != null) {
@@ -165,6 +168,11 @@ class _GameScreenState extends ConsumerState<GameScreen>
}
}
if (next.phase == GamePhase.lost) audio.play(Sfx.lose);
if (next.phase == GamePhase.lost && next.endless) {
ref.read(endlessBestProvider.notifier).record(next.score).then((isNew) {
if (mounted) setState(() => _endlessNewBest = isNew);
});
}
if (next.phase == GamePhase.won || next.phase == GamePhase.lost) {
ref.read(streakProvider.notifier).onStagePlayed(DateTime.now());
}
@@ -381,6 +389,18 @@ class _GameScreenState extends ConsumerState<GameScreen>
),
],
),
(GamePhase.lost, _) when view.endless => (
l10n.gameOver,
[
FilledButton(
onPressed: () {
setState(() => _endlessNewBest = false);
notifier.restart();
},
child: Text(l10n.playAgain),
),
],
),
(_, _) => (
l10n.stageFailed,
[
@@ -426,7 +446,24 @@ class _GameScreenState extends ConsumerState<GameScreen>
],
),
],
if (view.phase == GamePhase.lost && view.objectiveProgress > 0) ...[
if (view.phase == GamePhase.lost && view.endless) ...[
const SizedBox(height: 10),
Text('${view.score}',
style: theme.textTheme.displaySmall
?.copyWith(fontWeight: FontWeight.w900)),
const SizedBox(height: 4),
Text(
_endlessNewBest
? l10n.newBest
: l10n.bestScore(ref.read(endlessBestProvider)),
style: TextStyle(
color:
_endlessNewBest ? Colors.amber : Colors.white60,
fontWeight: FontWeight.w800,
),
),
],
if (view.phase == GamePhase.lost && !view.endless && view.objectiveProgress > 0) ...[
const SizedBox(height: 16),
SizedBox(
width: 88,
+1 -1
View File
@@ -16,7 +16,7 @@ class HudWidget extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_movesChip(theme),
view.endless ? const SizedBox(width: 48) : _movesChip(theme),
AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
transitionBuilder: (child, anim) =>