Michael Karén
Michael Karén's Blog

Michael Karén's Blog

How to Save High Scores in Local Storage

How to Save High Scores in Local Storage

Michael Karén's photo
Michael Karén

Published on Jan 11, 2021

5 min read

After creating a game, it would be nice to save our best scores. If we only save the score in memory it will be gone the next time we play. Instead, we can save the scores in the browser’s local storage.

This article steps through how to save high scores in local storage and then how to present them on the screen for the player. If you want to read about the game that inspired this article you can read about it here:

Local storage

With local storage, we can store data in the browser in the form of key-value pairs, where both the key and the value are strings. The data is persisted across browser sessions and its scope is limited to the origin where the script that accesses local storage resides.

Different browsers use different storages, so data is not shared between different browsers on the same computer — each browser has its unique storage.

The following snippets show how we can use localStorage:

// Add data
localStorage.setItem('myCar', 'Tesla');

// Read data
const car = localStorage.getItem('myCar');

// Remove specific data
localStorage.removeItem('myCar');

// Remove all data
localStorage.clear();

With this knowledge, we can start implementing our solution.

Load high scores

Let’s start by defining a couple of constants:

const NO_OF_HIGH_SCORES = 10;
const HIGH_SCORES = 'highScores';

Since we want to store an array we need to translate the array into a string before we save it and back to an array when getting it. For this, we can use the JSON object that contains methods for parsing JSON and converting values to JSON.

We can parse the string that we get from localStorage. If we don’t have any scores saved yet we can use the OR operator || to give a default value of empty array:

const highScoreString = localStorage.getItem(HIGH_SCORES);
const highScores = JSON.parse(highScoreString) || [];

We now have the high scores parsed into an array. Next, we need to check if a score is good enough to make the high score list.

Check for a high score

To get the lowest score on the list we can take the score from the last position in the array with the help of our constant NO_OF_HIGH_SCORES. If we don’t have a full list yet we can use optional chaining with the Elvis operator (?) and return a zero:

const lowestScore = highScores[NO_OF_HIGH_SCORES — 1]?.score ?? 0;

We have enough now to create a function checkHighScore():

function checkHighScore(score) {
  const highScores = JSON.parse(localStorage.getItem(HIGH_SCORES)) || [];
  const lowestScore = highScores[NO_OF_HIGH_SCORES - 1]?.score ?? 0;

  if (score > lowestScore) {
    saveHighScore(score, highScores); // TODO
    showHighScores(); // TODO
  }
}

And add it to the gameOver() function:

function gameOver() {
  // Other game over logic.

  checkHighScore(account.score);
}

As you can see we have a couple of remaining functions marked with TODO that we need to take care of. If we have a score good enough to make the high score list we need to save it and refresh the list.

Save high score

Now, we need to save the scores when the game ends and the player gets a score that qualifies on the top list. In addition to the score we need a name so let’s ask for it:

const name = prompt(‘You got a high score! Enter name:’);

When we have the name and the score we can create an object to save in the list:

const newScore = { score, name };

And when we have the new score that qualifies into the list we can:

  1. Add it to the list
  2. Sort the list
  3. Select the new high score list
  4. Save it back to local storage
function saveHighScore(score, highScores) {
  const name = prompt('You got a highscore! Enter name:');
  const newScore = { score, name };

  // 1. Add to list
  highScores.push(newScore);

  // 2. Sort the list
  highScores.sort((a, b) => b.score - a.score);

  // 3. Select new list
  highScores.splice(NO_OF_HIGH_SCORES);

  // 4. Save to local storage
  localStorage.setItem(HIGH_SCORES, JSON.stringify(highScores));
};

So, now that we have all this logic figured out we need to show the scores on the screen.

Show high scores

To show the best scores we need an element in the HTML that we can hook into. Let’s add an ordered list element with the id set to highScores:

<h2>HIGH SCORES</h2>
<ol id=”highScores”></ol>

Now, we need to retrieve the high scores from localStorage and show them on the screen. We can do this by using the array method map. It lets us go through the array and add an HTML ordered list item to each score in the array.

highScores.map((score) => `<li>${score.score}${score.name}`);

We can then get the ordered list element and add the list items to its innerHTML:

const highScoreList = document.getElementById(HIGH_SCORES);

highScoreList.innerHTML = highScores.map((score) => 
  `<li>${score.score} - ${score.name}`
);

We can run this when we initialize the game and every time there is a new high score:

function showHighScores() {
  const highScores = JSON.parse(localStorage.getItem(HIGH_SCORES)) || [];
  const highScoreList = document.getElementById(HIGH_SCORES);

  highScoreList.innerHTML = highScores
    .map((score) => `<li>${score.score} - ${score.name}`)
    .join('');
}

Now, we have a functioning high score list!

Conclusion

In this article, we added the functionality to persist our high scores in local storage. To help us format the data that we load and save from local storage, we used the JSON object. And to show it on the screen we added an HTML element as a hook to the DOM.

The next step to truly persist our high scores would be to add the high scores to a database. Maybe I will write about that next.

While I do, go play the game that inspired this article and make a high score:

Did you find this article valuable?

Support Michael Karén by becoming a sponsor. Any amount is appreciated!

Learn more about Hashnode Sponsors
 
Share this