Flutter Intermediate Lesson 117 of 135 2 min read
Save the High Score and Game Settings in Flame with shared_preferences
Save a high score, settings and progress in a Flutter Flame game with shared_preferences, with a runnable game that remembers your best score.
On this page
Players want to beat their best score, and they expect settings (sound on or off, unlocked levels) to be remembered. For small amounts of data like this, shared_preferences is perfect: it saves simple values on the device (and in the browser’s storage on the web).
Tap fast: a game that remembers your record
You have 5 seconds to tap the circle as often as you can. The best score is saved, so it is still there after you reload the page.
import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final prefs = await SharedPreferences.getInstance();
runApp(GameWidget(game: RecordGame(prefs)));
}
class RecordGame extends FlameGame {
RecordGame(this.prefs);
final SharedPreferences prefs;
int taps = 0;
int best = 0;
double timeLeft = 0;
bool playing = false;
late final TextComponent info;
@override
Future<void> onLoad() async {
camera.viewfinder.anchor = Anchor.topLeft;
best = prefs.getInt('best') ?? 0; // load the saved record
info = TextComponent(position: Vector2(16, 16));
world.add(info);
world.add(TapButton()..position = size / 2);
showInfo();
}
void tapped() {
if (!playing) {
playing = true;
taps = 0;
timeLeft = 5;
}
taps++;
}
@override
void update(double dt) {
super.update(dt);
if (!playing) return;
timeLeft -= dt;
if (timeLeft <= 0) {
playing = false;
if (taps > best) {
best = taps;
prefs.setInt('best', best); // save the new record
}
}
showInfo();
}
void showInfo() {
info.text = playing
? 'Taps: $taps Time: ${timeLeft.toStringAsFixed(1)}'
: 'Tap the circle to start! Best: $best';
}
}
class TapButton extends CircleComponent with TapCallbacks, HasGameReference<RecordGame> {
TapButton() : super(radius: 60, anchor: Anchor.center, paint: Paint()..color = Colors.teal);
@override
void onTapDown(TapDownEvent event) {
game.tapped();
scale = Vector2.all(0.9);
}
@override
void onTapUp(TapUpEvent event) => scale = Vector2.all(1);
}
Reading and writing
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('best', 42);
await prefs.setBool('soundOn', false);
await prefs.setStringList('unlocked', ['level1', 'level2']);
final best = prefs.getInt('best') ?? 0; // 0 if nothing saved yet
final soundOn = prefs.getBool('soundOn') ?? true;
Load preferences once, before runApp or in onLoad, and pass them to the game. Save straight away when something changes.
What to save where
| Data | Tool |
|---|---|
| High score, settings, unlocked levels | shared_preferences |
| A full save game (inventory, map state) | JSON in a file, or SQLite |
| Online leaderboards | Firebase or Google Play Games / Game Center |
More about the package in shared_preferences.
Try it yourself
Save the last five scores as a string list and show them in a column under the circle.