Saving and Loading Games with LocalStorage
Saving and Loading Games with LocalStorage
Saving a game's state is a necessary feature for games with anyhow long-term progression. Maybe you also want to store a highscore and a nickname for a fast-paced game with short playsessions. LocalStorage to the rescue! This global object allows for storing different string values and accessing them later. This feature works both in modern browsers and packed games. Combined with other handy features, we can store nearly any type of data!
Saving Simple Values
Saving and reading string values is pretty easy:
// Writing values to localStorage
localStorage.heroName = 'Isaac Newcat';
localStorage.heroTitle = 'The Allmighty';
// Reading values back
if ('heroName' in localStorage) { // was anything saved before?
// Read the values
this.name = localStorage.heroName;
this.title = localStorage.heroTitle;
} else {
// Do something with a missing data
requestNameAndTitle();
}
# Writing values to localStorage
localStorage.heroName = 'Isaac Newcat'
localStorage.heroTitle = 'The Allmighty'
# Reading values back
if 'heroName' of localStorage # was anything saved before?
# Read the values
@name = localStorage.heroName
@title = localStorage.heroTitle
else
# Do something with a missing data
requestNameAndTitle()
When it comes to numbers, dates, booleans, other stuff, we need to convert read values before using them.
// WRONG WAY
localStorage.heroLevel = 15;
// …later…
this.level = localStorage.heroLevel;
// this.level is now '15'. Wait, it's a string!
this.level += 1;
console.log(this.level);
# WRONG WAY
localStorage.heroLevel = 15
# …later…
@level = localStorage.heroLevel
# this.level is now '15'. Wait, it's a string!
@level += 1
console.log @level
this.level
is now '151'
! This is definitely not what we would expect. The reason is that localStorage
can only store strings, and anything else is turned into those. Because of that, we need to convert the values of localStorage
to the needed types.
// BETTER WAY
localStorage.heroLevel = 15;
// …later…
this.level = Number(localStorage.heroLevel);
// this.level is now 15. It's a number!
this.level += 1;
console.log(this.level);
# BETTER WAY
localStorage.heroLevel = 15
# …later…
@level = Number(localStorage.heroLevel)
# this.level is now 15. It's a number!
@level += 1
console.log @level
Here is how we can convert Date objects and Booleans:
localStorage.gameStartTime = new Date();
localStorage.hardcoreMode = false;
// later…
this.startTime = new Date(localStorage.gameStartTime);
this.hardcoreMode = localStorage.hardcoreMode === 'true';
localStorage.gameStartTime = new Date()
localStorage.hardcoreMode = false
# later…
@startTime = new Date localStorage.gameStartTime
@hardcoreMode = localStorage.hardcoreMode == 'true'
Storing Complex Objects
For anything beyound simple strings and numbers we need special encoding and decoding functions. Thankfully, there are such functions in JavaScript! They are JSON.parse(encodedString)
and JSON.stringify(complexObject)
.
var inventory = [{
name: 'A rusty axe',
type: 'weapon',
twoHanded: true,
durability: 0.87,
damage: [8, 11],
effects: {
poison: 1,
duration: 5
},
icon: 'BattleAxe_Old'
stack: 1
}, {
name: 'Health Potion',
type: 'consumable',
effects: {
regen: 5,
duration: 15
},
icon: 'Potion_Red',
stack: 15
}, {
// …other stuff
}];
// Save the inventory
localStorage.heroInventory = JSON.stringify(inventory);
// …later
// Load the inventory from the previously saved string
this.inventory = JSON.parse(localStorage.heroInventory);
inventory = [
{
name: 'A rusty axe'
type: 'weapon'
twoHanded: true
durability: 0.87
damage: [
8
11
]
effects:
poison: 1
duration: 5
icon: 'BattleAxe_Old'
stack: 1
}
{
name: 'Health Potion'
type: 'consumable'
effects:
regen: 5
duration: 15
icon: 'Potion_Red'
stack: 15
}
{
# …other stuff
}
]
# Save the inventory
localStorage.heroInventory = JSON.stringify inventory
# …later
# Load the inventory from the previously saved string
@inventory = JSON.parse localStorage.heroInventory
This is quite a complex thing! Here we encode an array, but you can pass both arrays and objects to JSON.stringify
.
What can't be encoded, though, are functions, Date objects as-is, circular references. But in most cases you won't even save such data in your games!
Using LocalStorage for Savegames in Catnip
In Catnip, you can use "save to storage" and "load from storage" to work with localStorage
. You should also use "is key in storage" to see if there is a savefile when you try to load data. Do remember that localStorage
stores strings only and you should convert any Numbers and other non-string values when you load values directly from localStorage
:
To store complex objects, you can use "serialize" and "deserialize" commands to turn them into strings and back. Here is an example: