17 - Storage

It would be nice to save a high score between plays! Replay provides a simple way to save things to local storage on the device.

In our top-level Game Sprite we add a highScore state field. In init we want to set this value to be what's saved in local storage. device.storage.getItem(key) returns a Promise containing the string value we saved under the key "highScore". When the Promise returns we update our high score field. If there's no highScore value saved from a previous game, then we set a default of 0.

In the gameOver callback we'll have the Level Sprite pass in the current score. If it's higher than our highScore state value, we replace the value in the Game Sprite's state and the store. Calling device.storage.setItem(key, value) will save the value on the device under the key passed in.

In the Level Sprite we need to pass the score into the gameOver callback.

In the Menu Sprite we read the Game Sprite's highScore value through a prop and display it. In order to have the high score text stand out a bit, we explicitly set the font name and size through the font prop.

BackNext
1import { makeSprite } from "@replay/core";
2import { Level } from "./level";
3import { Menu } from "./menu";
4
5export const Game = makeSprite({
6 init({ device, updateState }) {
7 device.storage.getItem("highScore").then((highScore) => {
8 updateState((state) => {
9 return {
10 ...state,
11 highScore: Number(highScore || "0"),
12 };
13 });
14 });
15
16 return {
17 view: "menu",
18 attempt: 0,
19 highScore: 0,
20 };
21 },
22
23 render({ state, updateState, device }) {
24 const inMenuScreen = state.view === "menu";
25
26 return [
27 Level({
28 id: `level-${state.attempt}`,
29 paused: inMenuScreen,
30 gameOver: (score) => {
31 updateState((prevState) => {
32 let { highScore } = prevState;
33 if (score > highScore) {
34 highScore = score;
35 device.storage.setItem("highScore", String(highScore));
36 }
37 return {
38 ...prevState,
39 view: "menu",
40 highScore,
41 };
42 });
43 },
44 }),
45 inMenuScreen
46 ? Menu({
47 id: "menu",
48 highScore: state.highScore,
49 start: () => {
50 updateState((prevState) => {
51 return {
52 ...prevState,
53 view: "level",
54 attempt: prevState.attempt + 1,
55 };
56 });
57 },
58 })
59 : null,
60 ];
61 },
62});
63
64export const gameProps = {
65 id: "Game",
66 size: {
67 width: 400,
68 height: 600,
69 maxHeightMargin: 150,
70 },
71 defaultFont: {
72 family: "Helvetica",
73 size: 24,
74 },
75};
76
Preview