Wednesday, January 1, 2014

Local Storage (Game Programming)

One of the things you might want to do when you are programming games is to save the game for the player between sessions. After all, phone games are all about short bursts of play that may need to be interrupted. A player is standing in line and ... time to leave the game. But coming back tomorrow is definitely a good thing.



There are two ways to save information to memory for later. The easiest is called Local Storage and is supported and I will cover it here. There is another, more complicated way called IndexedDB that is also supported, and allows more complex database storage management, and that will be the subject of a later post. But for the simple games I'm exploring, Local Storage is easy to use and doesn't require understanding of database theory. Local Storage has cousins named global and session, and you can read about all the storage family at https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage.

Local storage is very simple. You have some text data that you want to store. You store it with a specific name and retrieve it later by using that same name (called a key). This isn't necessarily data you want to sort through like you would with a database (that's what IndexedDB is for). You want to save and load, and that's it. The saving and loading takes place in a manner called synchronous, which means everything waits while you save your data. But since the data isn't across a network or to hard disk, the saving is pretty fast. You can't store more than 5MB, so this API is strictly for small potatoes.

If you know what cookies are, this API does much the same thing, but cookies are limited to 2KB. So use this for saving the status of your game, not a collection of last year's Twitter posts.

So, here's the code for a simple example of Local Storage.

<!DOCTYPE HTML>
<html>
 
  <head>
    <meta charset="UTF-8">
    <title>
      Local Storage
    </title>
 
    <script type="text/javascript">

        // Load event listener
      window.addEventListener("load", getLoaded, false);
       
      // Function called on page load.
      function getLoaded() { 
     
        // Save button listener
        myButtonSave.addEventListener(
          "mousedown", myClickSave,false);

        // Retrieve button listener
        myButtonLoad.addEventListener(
          "mousedown", myClickLoad,false);
         
        // Clear button listener
        myButtonClear.addEventListener(
          "mousedown", myStorageClear,false);
         
        // Length button listener
        myButtonLength.addEventListener(
          "mousedown", myStorageLength,false);       
         
        // Background color
        document.body.style.backgroundColor = "GreenYellow";

            // Output to console.
        console.log("The page is loaded.");
      }
     
      // Save button event handler
      function myClickSave() {
     
        // Display save inputs.
        info.innerHTML = "Input - Key: " + myKey.value +
          " Value: " + myData.value;
         
        // Save to local storage.
        localStorage.setItem(myKey.value, myData.value);     
      }
     
      // Retrieve buton event handler
      function myClickLoad() {
     
        // Get data from key.
        myValue = localStorage.getItem(getKey.value);
       
        // Create retrieve text string.
        myValue = "Retrieve - Key: " + getKey.value +
          " Value: " + myValue;
       
        // Display retrieve text string.
        info.innerHTML = myValue;  
      }
     
      // CLear the storage.
      function myStorageClear() {
     
        // Clear the storage.
        localStorage.clear();

        // Display storage cleared message.
        info.innerHTML = "Storage cleared!";   
      }
 
      // Determine how many storage items.
      function myStorageLength() {
     
        // Get the number of items.
        myLength = localStorage.length;
       
        // Display the number of items.
        info.innerHTML = "Items: " + myLength;
      }
 
      
    </script>
  </head>
 
  <body>
 
    <p id="info">Watch this space!</p>
 
    <p> Enter key here</p>
    <input id="myKey" autofocus>
    <br>
   
    <p> Enter data here</p>
    <input id="myData">
    <br>
   
    <button id="myButtonSave">Save</button>
   
    <p> Retrieve data with this key</p>
    <input id="getKey"><br>
   
    <button id="myButtonLoad">Retrieve</button>
    <br><br>
   
    <button id="myButtonClear">Clear</button>
    <br><br>
   
    <button id="myButtonLength">Number of Items</button>

  </body>

</html>


When you load it into the Firefox OS Simulator or into your Firefox OS phone, it looks like this:



To get started, press on the box below "Enter key here" and enter a word that will be the key for your data. Next, go to the box below it and enter the data you want to save. Then press the button that says "Save". I picked "a" for the key and "b" for the data, but any text (numbers and letters will do). The results should look like this:


The values you entered should be at the top (where it used to say "Watch this space!"), You've now entered data with key. The data will stay on your phone until you clear it out. Kill the app and when you bring it back, the data will be there. (You kill an app by doing a long press on the Home button and clicking on the upper left of the app you want to kill.)

Next, enter another key-value pair. I picked "c" and "d" and pressed Save. My new results should look like this:


We now have two key-value pairs. If you'd like to verify this, press the "Number of Items" button and you should see this:


And now the exciting part. Press on the box just below "Retrieve data with this key" and type in a key that is associated with some data. I picked the key "a" and pressed the "Retrieve" button. Here is what I got:


The key "a" retrieved the value "b". Remember, you can use any text for the key and any text for the data you store. If you want to store something that is not text, you must convert it to a number; easy to do in JavaScript. In my example, if you type the number 1, it will be treated as text.

Next, when you're finished with your testing, clear out the storage by pressing on the "Clear" button.


You'll see the message at the top, "Storage cleared!" And finally, to see that the storage is gone, press on the "Number of items" and you'll get this:


The number of items is 0!

The code is actually pretty simple. It follows the pattern that I've been using in other examples. The buttons are created in the body of the page (and I just laid them out loosely with break tags). Each button has an event listener associated with it, and a function that will handle the event.

Local Storage API

The code for Local Storage is pretty simple. You use the localStorage object and its methods and properties. Here's a quick list of the methods and properties:

     setItem(key, data) - stores data by using a key

     getItem(key) - retrieves data by using a key.

     clear() - clears the storage. Note that this is a method and needs those parentheses.

     length - indicates the number of items. Note that this is a property and does not use parentheses.

The rest of the code uses the value of the input boxes (for example, the box with the id of "getKey" will be used in getItem as getKey.value) and display paragraphs (with the id of "info" will be used as info.innerHTML).

All in all, very simple. But crucial for making your player happy. They want to come back and play again, so make it easy for them! The Local Storage API is easy to use and works. So use it!

This post concludes my thoughts on what are the basics needed to create a game in HTML5 with Firefox OS. Moving, colliding, tilting, music, touching, etc. There's always more, but these are the simple tasks that most games will use. It's been fun for me to explore each one and I hope it's been interesting for you. Blogger tells me I've had a total of 12,000 page views since I started this blog in early October and I've written 60 posts. I don't know if that's a lot or not very much, but like I say, I'm having fun!

Next I'll start by making a complete (but small) game. I may even enter it in the One Game a Month contest http://www.onegameamonth.com/. I'd like to spend the next year exploring various game types (all simple and small) and I'm also thinking of exploring some of the game libraries such as Phaser (http://phaser.io/). After that, I'd like to talk about mechanics, a bit like Three Hundred Mechanics (http://www.squidi.net/three/) but at a lower level. And maybe put some games in the Marketplace. But right now I'm having fun just sorting out ideas and focusing on Firefox OS. I also might write a book. Well, that's a lot of stuff to do, but I am obviously interested in all this and having a lot of fun.

Stay tuned, but not iTuned!