Friday, January 10, 2014

IndexedDB (Game Programming) - revised

Sometimes I can't let an idea go. I wrote a simple post on Local Storage and thought that would be all that needed to be said in terms of saving high scores for your game! Well, it turns out that Local Storage has been proved harmful (just like GOTO) and that you don't want to use it in Firefox OS. Synchronous programming is not good!

Lucky for us, the Firefox OS team has created a small library called async_storage.js that covers the same territory as Local Storage. I wrote about it here: http://firefoxosgaming.blogspot.com/2014/01/asynchronous-storage-game-programming.html. Done!

Well, not quite, because there were a few nits I had to add about how it worked. And there was that nagging feeling that maybe I should dig into IndexedDB, which is what async_storage.js is based upon. As a low-level kind of guy, I like knowing what's under the hood. Well, IndexedDB isn't simple, but it's not really that hard. And it's a great tool to add to your toolbox. Not just for saving high scores, but for any complicated stuff. I remember when I worked on a large adventure game in the 80's and the head of the project said that adventure games are really all about databases!

Okay, so what is IndexedDB? Essentially it is a database that can be stored on your phone. When you turn off the phone and come back later, the data is still there. But there are a few different types of databases (highly simplified).

Flat

Flat databases are just tables. You have rows and columns and you put data in and get it back later. Specify the type and width of the columns and you're done. This is how Excel and other spreadsheets work. You've all seen that somewhere, I'm sure. Are there any spreadsheets available for Firefox OS?

Relational

In the 90's, relational databases came into their own and became standard. Essentially you have a bunch of tables and you relate them to each other. If you specify your data carefully, you can do very powerful things. Or mess things up quickly. The language that most people use for this is SQL (Structured Query Language). Right now this is what most corporations use.

No-SQL

A recent trend is to do away with SQL and make simplified databases that work with key-value pairs. They don't require SQL and these databases are hot right now. IndexedDB is one of these. If you'd like to know more about no-SQL databases, I recommend a cool book called Seven Databases in Seven Weeks: A Guide to Modern Databases and the NoSQL Movement. A nice read an an eye opener if all you know about databases are flat or relational.

IndexedDB

IndexedDB is supported in Firefox OS, Firefox desktop, Firefox for Android, Chrome, Internet Explorer, but not Safari and a few other mobiles. We only care about the ever-growing Firefox family and we're good with IndexedDB.

As usual, the Mozilla Developer Network (MDN) covers IndexedDB well. Start at a great overview here: https://developer.mozilla.org/en-US/docs/IndexedDB/Basic_Concepts_Behind_IndexedDB. You'll want to browse through the large API starting here: https://developer.mozilla.org/en-US/docs/IndexedDB.

Two tips for reading the docs:

  1. The docs are laid out as interfaces (for example, IDBObjectStore). You're not going to type that. You're going to type something.objectstore.something. The IDBxxx name is for C++ developers and that's not you. That's really more for the Mozilla developers and the original W3C specification.
     
  2. The sample code is confusing and might be out of date. The reference has lots of code snippets with references to earlier definitions not included. You can figure it out, but because IndexedDB is still pretty new, there aren't a lot of helpful samples and tutorials elsewhere. Part of that is that there are several ways to skin this kind of cat, and the API is complicated. And because this is a different type of database, some things aren't always there or named what you think they might be. But it does work! Not really a criticism of MDN, because I know how much they have to do and how little resources they really have!
So with that said, the main thing to understand is that you store your data as key-value pairs. The value is the data you want to store and retrieve, and key is the label for that data. For example, you might have a bunch of names for your pets. The names would be keys and the type of pet would be the data. You want unique keys (unless all your pets are named Spot) and each key will identify a particular pet. So "Rover" would be your "dog" and "Felix" would be your "cat". You can also index your data so "Pets" might be your key and Pets[1] would be a particular pet. There are a lot of ways to skin these pets (please forgive the American slang). Indexing and other manipulation can be very powerful. And everything is asynchronous, so you won't have problems with waiting.

Indexed DB Steps


Indexed DB requires a few steps that you will use every time. Learn them and it is actually pretty easy. Here are the steps:
  1. Open your database. If there is no database, one will be created for you.  You need to specify a name and a version. Tip: don't use decimals for your version.
  2. Create a store. You can have more than one store in your database. Think of it as a table. You could have one store for your cats and another for your dogs. You only need to do these first two steps once. Each time you change the version, you need to do it over again. You'll need to specify the store name and a keyPath. The key path (or just key) is just the way you will sort your data. Make sure that the key will be unique for your data. If you have two dogs named Spot, you're in trouble.
  3. Set up a transaction. A transaction is a specific change to the database. You're going to add, put, get, or delete data, using key-value pairs. But before you can do that, you must set up the transaction. To set up the transaction, you need the store name. All transactions are tied to a specific store.
  4. Add, put, get, and delete your data. These operations make up a transaction. You can probably figure out what each operation does, but add will add to the database while put just replaces something that is there (or adds it if nothing is there). The commands take different parameters, depending on what you are doing. For example, add and put will require a key and value, but a get and delete only requires the key.
     
  5. Check to see if errors happen. You'll want to do this. Always. Luckily you can set up events easily to do this. onsuccess and onerror are your friend.
Essentially you'll set up things so you only do steps 1 and 2 once for every database version, and the onupgradeneeded event takes care of that for you. Steps 3 and 4 you do each time you want to add, put, get, or delete data. There's plenty more and you can have fun with indexing all day. But don't forget to do step 5 for every action you take. Be careful out there, people!

I've created a very simple sample that will show you the basic code to do IndexedDB. I'm only creating one database, one store, and one item (with one key-value pair). In keeping with game design and making this really, really simple, I'm just storing the value of a score, letting you generate random scores, and then storing them in the database and getting them back again and displaying the results.

The Code

So here's the code, tested and run on the Geeksphone Peak with Firefox OS 1.1.

<!DOCTYPE HTML>
<html>
 
  <head>
    <meta charset="UTF-8">
    <title>
      IndexedDB
    </title>
 
    <script type="text/javascript">
   
    // Global variables.
    var highScore = 0;
    var myDb;                    // Database object
    var myDatabase = "FoxBase";  // Database name
    var myVersion = 1;           // Database version
    var myStoreName = "myScore"; // Database store name
    var myStoreObject;           // Database object store
    var myTrans;                 // Database transaction 
    var flag = 0;                // Flag for initial data.   

        // 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 = "Coral";
       
        // Generate a random score.
        randomScore = Math.floor(Math.random()*10000);
        info.innerHTML = "High score: " + randomScore;
       
        // Initialize with name and version.
        // If no database exists, one will be created.
        myRequest = window.indexedDB.open(myDatabase,
          myVersion);
            
        // This is called on version change.
        // Fired first time database is created.
        // Not fired again unless new version created.
        myRequest.onupgradeneeded = function(e) {
       
          // Save result of version change.
          myDb = e.target.result;
         
          flag = 1; // First time through.
         
          // Kill duplicate name if there is one.
          if(myDb.objectStoreNames.contains(myStoreName)) {
            myDb.deleteObjectStore(myStoreName);
          }
         
          // Make an object store.
          myObjectStore = myDb.createObjectStore(myStoreName,
            { keyPath: "initials" });
           
              // Provide feedback.
              console.log(myStoreName + " object store added!");
            }
                       
        // Was the request successful?
        myRequest.onsuccess = function(e) {
         
          // Provide feedback.
              // Database name and version.
          console.log(myDatabase + " version: " +
            myVersion + " loaded!");
              // Database state.
          console.log("Database request state: " +
            myRequest.readyState + "!");
           
          // Save reference to database.
          // You need this if not first time.
          myDb = e.target.result;        

          // Initialize data only if first time.
          if (flag==1) {
         
            // Initialize the score.   
                // Get the transaction.
                myTrans = myDb.transaction([myStoreName],
            "readwrite");         
            // Get the store object.
                myStoreObject = myTrans.objectStore(myStoreName);
         
            // Put the data you want to save into the store.
                // The key is "initials" and the data is "score".
                // Insert the current random score.         
            myStoreObject.put({
              "score" : highScore,
              "initials" : "ABC"
            });   
         
                // Provide feedback.
                console.log("Score initialized to zero.");
          }           
        }
       
        // Did the request fail?
        myRequest.onerror = function(e) {
       
          // Provide feedback.
          alert("Error: " + e.target.errorCode);       
        }

            // Page loaded and initialized.
        console.log("The page is loaded!");
      }
     
      // Put button event handler
      function myClickSave() {
     
          // Open a transaction on the database.
        myTrans = myDb.transaction([myStoreName],
          "readwrite");
       
            // Get the store object.
        myStoreObject = myTrans.objectStore(myStoreName);
       
            // Put the data you want to save into the store.
            // The key is "initials" and the data is "score".
            // Insert the current random score.
        myRequest = myStoreObject.put({
          "score" : randomScore,
          "initials" : "ABC"
        });   
       
            // Provide feedback.
            console.log("New score added!");   
        putScore.innerHTML = "New score added!";     
        }
     
      // Get button event handler
    function myClickLoad() {
     
        // Open a transaction on the database.
      myTrans = myDb.transaction([myStoreName]);
       
          // Get the store object.
      myStoreObject = myTrans.objectStore(myStoreName);
       
          // Get the item name corresponding to the "initials".
      myRequest = myStoreObject.get("ABC");
       
          // Did we get the score?
          myRequest.onsuccess = function(e) {
       
            // Display the actual score we got.
            console.log(myRequest.result.score);
        getScore.innerHTML = myRequest.result.score;       
          }    
    }
     
      // Delete button event handler.
      function myStorageClear() {
     
        // Delete the database.
        // Use this only for testing!
        window.indexedDB.deleteDatabase(myDatabase);
       
        // Oh, noes, you killed the database!
        console.log("You deleted the whole database!");      
      }
 
      // Create new score button event handler.
      function myStorageLength() {

        // Generate a random score.
        randomScore = Math.floor(Math.random()*10000);
        info.innerHTML = "High score: " + randomScore;
      }
      
    </script>
  </head>
 
  <body>
 
    <p id="info">Watch this space!</p>
   
    <p>Put something in the database.</p>
    <p id="putScore">PUT SCORE</p>
   
    <p>Get something from the database.</p>
    <p id="getScore">GET SCORE</p>
   
    <button id="myButtonSave">Put Score</button>
    <br><br>
   
    <button id="myButtonLoad">Get Score</button>
    <br><br>
   
    <button id="myButtonClear">Delete Database</button>
    <br><br>
   
    <button id="myButtonLength">Create New Score</button>

  </body>

</html>


This is about the smallest I could boil it down to and still have a complete example that lets you see the putting and getting happen on your phone. If you close the application and kill it, the data will still be there the next time you load the app. Magic!

What It Looks Like

 When you load the app into your Firefox OS phone, here is what it looks like:


The top line is the high score. The next two lines will tell you about the Put operations and the two after that will tell you about Get operations. The four buttons will Put the score into the database, Get the score from the database, delete the database, and generate a new score from a random number.



The above screen shows what happens if you press the Get button. The initial score is set to zero, so if you get it, that is what you get, and it is displayed below the heading "Get something from the database." The randomly generated high score is at the top, but is not yet in the database.


The above screen shows what happens when you press the Put button. Under the "Put something in the database" it says "New score added!" You're just being notified that a score was added. The data that was added was whatever the high score was, as displayed at the top of the screen.


The above screen shows what happens if you now press the Get button to see what you stored with the Put button. You'll see that the number is the same as the high score.

The "Create New Score" button just generates a new high score randomly, letting you save it with the Put button if you want to test it.

The "Delete Database" was something I put in for testing. It just deletes the database. You only need this if you are changing the code and need to delete the database to start over again with the same version. If you delete the database, you'll need to completely kill the app and start over again. On the phone, you do a long press on Home and tap on the upper-left-hand corner of the app you want to kill.

How Does It Work?

This is just a simple HTML5 page with buttons and text in the body. I had a bunch of globals and event listeners for the buttons and their corresponding event handlers. The code starts in the handler that is loaded when the page loads.

Step 1 - Open the Database

The first step for Indexed DB is to open the database.

        myRequest = window.indexedDB.open(myDatabase,
          myVersion);


You just open a database with a name and version (defined in the globals). The result of this will be stored as a request that you can use to  use to see if your request to open worked.

Step 2 - Create a Store

       myRequest.onupgradeneeded = function(e) {
       
          myDb = e.target.result;
         
          if(myDb.objectStoreNames.contains(myStoreName)) {
            myDb.deleteObjectStore(myStoreName);
          }
         
          myObjectStore = myDb.createObjectStore(myStoreName,
            { keyPath: "initials" });
           
              console.log(myStoreName + " object store added!");
            }

You want to do this only when the onupgradeneeded event takes place, and that takes place once in a lifetime for each version of your database. First you see if there is a store with that name already, and if there is, you delete it and make one with the same name. You want to be careful. Who knows what is already hidden away in that database? The store is created with a name and a keyPath. The name can be anything and I chose "initials" as my key because it might be fun to expand this and let people save scores with their initials, just like in the arcade machines. I also added a console.log statement that says the store was added. Maybe it wasn't really, but with JavaScript, if a log doesn't print out, something went wrong. But fortunately there's a way to tell what happened.

Step 2.5 - Did it happen?

        myRequest.onsuccess = function(e) {
         
          console.log(myDatabase + " version: " +
            myVersion + " loaded!");
          console.log("Database request state: " +
            myRequest.readyState + "!");


          myDb = e.target.result;


This code will be triggered if the creation was successful. It logs the database name and version, and also the ready state. The ready state will tell you if the loading is over or still happening.

I also added a reference to the database itself here with the variable myDb. This same line was in the onupgradeneeded event handler. Why twice? Because if I just have it in the onupgradeneeded handler, it will only get created the first time through. That makes it difficult to use again for the button event handlers, who also use myDb to get a reference to the database. You can only get that reference by opening the database and using a handler. Because the onupgradeneeded handler is asynchronous, you can't assume that it will get the reference from the database open. So doing it twice is the only way to make sure! With asynchronous programming, you must be sure. You can't assume.

Step 3 - Start a transaction

Now that the database and store are prepared, it's time to do a first transaction, to set the score to zero. We're only going to do this once. You want this code in the onsuccess event handler because it might not run if you try to do it in the onupgradeneeded handler. But that handler gets called when the database is opened (every time you run the app) and again when you create the store inside the upgradedneeded handler. So my hackish solution is to create a flag that starts out at 0 as a global and is set (set means flag =1) inside the onupgradeneeded handler. Then when the success event handler is called, the flag will determine whether the initializing transaction takes place.

                                flag = 1; // First time through.

Then, in the onsuccess event handler, you start the transaction like this:

             if (flag==1) {

               myTrans = myDb.transaction([myStoreName],
                 "readwrite");                     

This will open a transaction. Notice that the store name has brackets around it, indicating that it is really an array. We're only using the first item in the array, but the transaction folks like to know these things. The transaction is readwrite, indicating that you can read or write.

Note that this transaction is actually part of the onsuccess event handler. You don't want to even try to create something if the object store wasn't successfully created.

Step 4 - Put the data

          myStoreObject = myTrans.objectStore(myStoreName);
                  
          myStoreObject.put({
            "score" : highScore,
            "initials" : "ABC"
          });   
         
          console.log("Score initialized to zero.");

        }

This is still part of the onsuccess event handler. First you get the object store by using its name and then you put the data in that store using a key-value pair. The key is "initials" and you must always use this to store your data, and you must make sure that each key is unique. For simplicity, I chose simple keys and values, but for more complicated data, you'll want to have an index that is unique so that all your data is solid.

Notice that the commands are tied not only to the specific store, but to a specific transaction.

And note, also, that this initialization only takes place once. If you kill the app and come back later, the data will not be initialized but will be whatever you last saved it as.

Finally, I used a console message to say that the Put took place and what it was about.

Getting the Data

I have a button that you can press to get the current value in the database of the score. Here's the code.

    function myClickLoad() {
     
      myTrans = myDb.transaction([myStoreName]);
       
      myStoreObject = myTrans.objectStore(myStoreName);
       
      myRequest = myStoreObject.get("ABC");
       
      myRequest.onsuccess = function(e) {

        console.log(myRequest.result.score);
        getScore.innerHTML = myRequest.result.score;       
      }    
    }


This event handler creates a transaction using values from the global variables. This needs the database and store name. The database name was created when you initialized the database with onupgradeneeded. You need to store these as globals and the variables are saved with the database.

This is similar to the initialization of the score. You get your transaction, get your store, and then you get your data, based on the "initials" key. The particular key is called "ABC" and the Get gets it. Get it? Then you see if you got it with the event handler. If you did, the score will be:

       myRequest.result.score

The "score" is the matching part of the pair that corresponds to "initials". The result is the result of the event, which was to get the data.

Putting the Data

This is similar to getting the data.

      function myClickSave() {
     
        myTrans = myDb.transaction([myStoreName],
          "readwrite");
       
        myStoreObject = myTrans.objectStore(myStoreName);
       
        myRequest = myStoreObject.put({
          "score" : randomScore,
          "initials" : "ABC"
        });   
       
          console.log("New score added!");   
          putScore.innerHTML = "New score added!";     
      }


You start a transaction, get the store, save the data with a key and value. The names of the key and value pairs are "initials" and "score" and the data that is saved in this case are "ABC" and the value of randomScore.

Deleting the Database

Don't try this at home! You only should do this while you are programming, but I thought I'd leave it in for your use. Once a database is deleted, you need to close the browser and kill it thoroughly dead.

     function myStorageClear() {
     
        window.indexedDB.deleteDatabase(myDatabase);

        console.log("You deleted the whole database!");      
      }

Again, use global variables.

Generating a New Score

I put this in a button event handler.

     function myStorageLength() {

        randomScore = Math.floor(Math.random()*10000);
        info.innerHTML = "High score: " + randomScore;
      }

Ignore the function name and button id names. I wanted to use the same UI as my earlier examples. Probably not a good idea. There isn't any method or property that I could find for IndexedDB that tells how many items are in a store. Maybe that's by design?

This just uses good old Math to make a random number and puts it on the screen.

That's It!

I hope you enjoyed this somewhat winding trip down the database lane. IndexedDB isn't that hard to use but it satisfies all the requirements for good database management in HTML5 and is completely supported by Firefox OS.

(Well, I take that back. There's a synchronous version of IndexedDB that will be tailored for Web Workers, but it's not ready yet. Web Workers are cool but that's the subject of a different post, later, much later.)

Now I'm back to review some games and then to create a simple game and see if I can put it in the Marketplace. I'll do that over a series of posts. Stay tuned, but not iTuned!

Not Quite

If you read this in the last few hours, I'm sorry to tell you that I made two errors my my logic.
  1. The score gets initialized every time. The code is the right place, you can't read and write data until the onsuccess event fires. The problem is that the same event is firing at two different times. When you open the database it fires, but it also fires when you create the store. My quick solution to this is to create a flag that is only set when the onupgradeneeded fires (the first time through). Then, when the onsuccess event triggers, if the flag is set, the data is initialized. Otherwise not. It is very important to be aware of the flow, especially with asynchronous timing. If you try to read or write data before the database is ready, you'll get an error.
     
  2. The myDb was set in the onupgradeneeded event handler. That would mean that in subsequent times through, the myDb variable wouldn't have a value. So I added it to the onsuccess event in the main routine. That way, whichever event is triggering the onsuccess, the myDb variable is created, which is the way to reference the database in the other event handlers.
I've fixed the code above and I'll put a note in the comments and tweet the changes. I apologize for these errors. No one pointed them out, but the wit of the staircase prompted me to go back and look again, only to see that I had made a subtle but important error. Two errors, not related.

IndexedDB is a bit tricky because it is asynchronous, but I think I've wrapped my head around it and I hope you will too!

Wednesday, January 8, 2014

Asynchronous Storage (Game Programming)

Recently, I wrote this post (http://firefoxosgaming.blogspot.com/2014/01/local-storage-game-programming.html) on Local Storage, a simple way to store data on your phone between sessions. Simple, easy, works on all browsers. Or so I thought! But storage turns out to be more complicated.



I got some comments from Gabriele Svelto and Dietrich Ayala. They told me that Local Storage is not recommended for Firefox OS. Since they are both on the FxOS team, that's good enough for me. Turns out that for Firefox OS, Local Storage is a performance and I/O problem.

This isn't terribly surprising, giving how critical computing is on a phone with limited resources. One thing I've learned over the years is that synchronous programming can be a problem. What is synchronous programming? It's where you make a call and wait until the call is returned. That's an oversimplified answer, but when things are tight, you don't want to wait.

So if you use Local Storage, your call will take place and nothing else can happen while you are doing it. That can be fine if your calls are small and there's nothing else going on and you have plenty of resources. But you can't afford to have your phone freeze up.

The opposite of synchronous programming is ... wait for it, asynchronous programming. What a difference that first letter of the alphabet makes (if you're using the English alphabet - for the tinkopar, it would be t). Asynchronous programming says that you can make a call and then go do something else. You register a callback (a separate function) and when your call goes through, the function will respond and take action. How cool is that?

So Local Storage is out. Don't use it on Firefox OS. What's the alternative? If you are doing any kind of serious game, you want to let the player save their game for another day. And memorizing codes went out with old game consoles. Well, there's another way to save data, and its name is IndexedDB. This is a more recent way to save data, and is asynchronous. If you want to know more about it, see this page on MDN https://developer.mozilla.org/en-US/docs/IndexedDB. This has been around in Firefox for a long time, but other browsers were slow to catch up and Safari still isn't there at all and some of the other mobile browsers are AWOL as well. But it works in Firefox OS and works well.

However, the API for IndexedDB is a bit more complicated. It uses real database concepts and you need to understand how it works. It uses transactions and the DOM, but not SQL (I hate SQL, don't you?) Read more about it here on MDN: https://developer.mozilla.org/en-US/docs/IndexedDB/Basic_Concepts_Behind_IndexedDB

So you can't use Local Storage and you may not want to use IndexedDB if you're starting out. What is a game programmer to do?

Riding to the rescue of overwhelmed developers everywhere, Mozilla has made a compromise API that is almost as simple as Local Storage, but uses IndexedDB under the hood. This technology comes in the form of a small JavaScript library called async_storage.js. You can get it here: https://github.com/mozilla-b2g/gaia/blob/master/shared/js/async_storage.js. Copy it all and save it as a file named async_storage.js. But before you do, make sure you understand that this is open source under the Apache license and that you follow all the rules. If you don't know those rules, read them here: https://github.com/mozilla-b2g/gaia/blob/master/LICENSE.

Once you've got your async_storage.js file prepared, save it to your project. To use this cool piece of software, insert this line into your web page:

    <script src="async_storage.js"></script>

If the async_storage.js file isn't in your root, change the line above to tell the packager where it is.

What does this new asynchronous storage API do? Pretty much exactly what Local Storage did. It uses the same concepts and names, but with one small difference. Every method must include an extra function call as a callback. And there are no properties now, only methods.

Maybe an example would be nice. I'll use the same example I used in my Local Storage post: http://firefoxosgaming.blogspot.com/2014/01/local-storage-game-programming.html. Here's what the UI looks like.



Enter a key and value in the top two boxes and touch Save to ... save. Retrieve your data with a key you enter in the third box and touch Retrieve. Clear the storage with Clear and get the number of key/value pairs by touching the Number of Items button. Each action will produce a message at the top of the screen (where it says "Watch this space!"

And here's the new code, run and tested on my brand new shiny Geeksphone Peak.

<!DOCTYPE HTML>
<html>
 
  <head>
    <meta charset="UTF-8">
    <title>
      Async Storage
    </title>
   
    <script src="async_storage.js"></script>
 
    <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() {
     
        // Save data with key.
        asyncStorage.setItem(myKey.value, myData.value,
          function() {
            console.log("New value stored.");
            info.innerHTML = "Input - Key: " + myKey.value +
              " Value: " + myData.value;      
        });     
      }
     
      // Retrieve button event handler
      function myClickLoad() {
     
        // Get data from key.
        asyncStorage.getItem(getKey.value,
          function(myValue) {
            console.log("The value is ", myValue);
            myValue = "Retrieve - Key: " + getKey.value +
              " Value: " + myValue;          
            info.innerHTML = myValue;
        });           
      }
     
      // Clear button event handler.
      function myStorageClear() {
     
        // Clear the storage.
        asyncStorage.clear(function() {
          console.log("Storage cleared!");
          info.innerHTML = "Storage cleared!";
        });
      }
 
      // Number of Items button event handler.
      function myStorageLength() {

        // Get the number of items in storage.
        asyncStorage.length(function(myLength) {
          console.log("The number of items is ",  length);
          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>


Short and simple. Enter some key/value pairs, retrieve them, add more, count them, and clear. If you don't clear the database, and you shut down and come back tomorrow, the data will still be there!

The API details are actually in the JavaScript file, but here's a quick summary:

setItem - saves an item with a key/value pair.

getItem - gets an item value with a specific key.

removeItem - removes an item with a specific key.

clear - clears the database.

length - tells you how many key/value pairs are in the database.

key - gives you the value at a specific location in the database.

Note on the key API: the order stored isn't necessary guaranteed, so use this only to loop through all the items.

Sounds pretty much like the Local Storage API. But there are two differences:

1. You must use the asyncStorage object for all your calls and attach your methods to it.

2. Each method must have an additional parameter that specifies the function that will be called when the asynchronous call is done.

This last one is cool and not that hard. Here's an example:

Instead of typing:

        asyncStorage.clear();

You must type:

       asyncStorage.clear(myClearCallback);

Then create a function called myClearCallback() that will be called when the asynchronous call returns. You don't need to call it myClearCallback, any function name is fine as long as it is unique and has a function to go to.

If you don't want to create a separate function for your callback, you can use an anonymous function. Anonymous functions look like this and you use them inside the parameter. Here is an anonymous function:

       function() {
          // Stuff here you want to have happen
          // when the asynchronous call returns.
       }

It looks like this if you insert it into the asyncStorage.clear function:


        asyncStorage.clear(function() {
          console.log("Storage cleared!");
          info.innerHTML = "Storage cleared!";
        });
 

This displays a console.log message and a UI message when the asynchronous call returns.

The syntax is a bit overcrowded with punctuation, but you can always have a separate callback function if you want. By the way, callbacks are called by event listeners, I just haven't called them callbacks before.

This is a little different from programming you may have seen, in that you can no longer type something like:

       myValue = localStorage(key);

Values are not returned directly. That would be synchronous! So you must insert a callback function in your parameters. If the localStorage didn't have any parameters (like clear and length), you have to add one (and length is now a function, not a property). If localStorage had parameters, add one more!

I used anonymous functions for my four functions. Here is how each bit looks:

setItem

        // Save data with key.
        asyncStorage.setItem(myKey.value, myData.value,
          function() {
            console.log("New value stored.");
            info.innerHTML = "Input - Key: " + myKey.value +
              " Value: " + myData.value;      
        }); 
    

getItem

        // Get data from key.
        asyncStorage.getItem(getKey.value,
          function(myValue) {
            console.log("The value is ", myValue);
            myValue = "Retrieve - Key: " + getKey.value +
              " Value: " + myValue;          
            info.innerHTML = myValue;
        });       
    

clear

        // Clear the storage.
        asyncStorage.clear(function() {
          console.log("Storage cleared!");
          info.innerHTML = "Storage cleared!";
        });


length

        // Get the number of items in storage.
        asyncStorage.length(function(myLength) {
          console.log("The number of items is ",  length);
          info.innerHTML = "Items: " + myLength;        
        });  


myKey  and myData are defined by their input boxes.

So this isn't really that hard to use and lets you be asynchronous with your data. The folks at Mozilla were geniuses to think of a way to be asynchronous with an API that was synchronous. All you need to do is load in the tiny library and add a callback for each function you use.

NOTE: The callbacks are not required for setItem() and clear(). But I recommend using them so you can be sure your items are saved or cleared. Remember the poster on Mulder's wall: "Trust No One." You will need the callbacks for getItem() and length() because otherwise you won't get the data you requested.

NOTE: After more discussion, the callbacks don't tell you much more than something worked. If it didn't work, something very wrong happened. But usually they work. If you need more confidence about success and failure, check out my post on IndexedDB at http://firefoxosgaming.blogspot.com/2014/01/indexeddb-game-programming.html. async_storage.js uses IndexedDB under the hood so if you want more than simple, check out IndexedDB.



Tuesday, January 7, 2014

A Bit More About Geeksphone Peak (Hardware Review)

A few more notes about the Geeksphone Peak that I received over the weekend.


I love it even more! When I was developing on the ZTE Open, every single time I would push an app I wrote to the ZTE, I would have to reboot the phone. This may be a bug for Firefox OS v1.0, but for Geeksphone Peak, at v1.1, I don't need to reboot. When the app makes its leisurely way down the USB cable from my PC to my phone, the icon just ... appears. No reboot, no problem. How cool is that?

I did have one problem that I want to share with you because if you use one Firefox OS phone and then switch to another, the Windows PC doesn't recognize your new phone. This may be a Windows problem (ha ha) but the issue turns out to be that Windows thinks you are still using a ZTE Open (in my case) and doesn't recognize your new Geeksphone Peak.

The fix is simple (if you're used to battling Windows). I have Windows 7 and what I had to do was go to the Control Panel, visit the Device Manager, and find the ZTE Open driver. Then uninstall the ZTE driver, reboot your PC, and then install a new driver from Geeksphone.

If you're lucky, the driver will install itself magically and you won't have to do anything. If you're not so lucky, you may have to download the driver from Geeksphone. The driver is here: http://downloads.geeksphone.com/drivers/usb_driver.zip. Download it, unzip it, and then reboot. Windows will try to install a driver, will say (maybe) it can't find one, and then you can direct Windows to find it in the folder you unzipped the Geeksphone driver at.

Everything should work fine after that, and it does for me.

And actually super-fine, because I can now load lots of my own apps onto my new phone. I still need to use the Simulator, but it works fine for me. I'll be eager to use the App Manager to load and view apps when I can get the Geeksphone Peak to update to version 1.2, which may happen soon!

So, just for your amusement, here's where the Geeksphone Peak driver is now located in Device Manager.


And, it now also gives me to USB drives to play with in File Manager:


Drive F: corresponds to the Internal Media Storage section of the phone. If you don't want to see this, you can disable it from the Media Storage section by deselecting the "Share using USB" button under the heading Internal Storage.

Drive G: corresponds to the SD Card Storage section of the phone. This is where you can put your music and photos.

If you select SD Card as the default media location, your screen shots will go there. One of the other cool things about the Geeksphone Peak is that it has 1GB of storage built in. The ZTE Open has (without an SD card), a whopping 6.4MB Device Storage, and that doesn't seem to be accessible to the PC. (Well, a lot of phones require some kind of SD card, but it is cool to see that you can live without one on the Geeksphone Peak.)

Without any reservation, I recommend the Geeksphone Peak for its speed, memory, and upgraded OS version. Travel over to Madrid and grab one while they are still available. I tried to order mine three times before but they were always out of stock. (But the ZTE Open was a bargain that got me started, so I'll recommend that if you only have $79 and you are patient.)

So now I can get back to work writing about games and game programming, this time armed with my ultra-powerful Geeksphone Peak. Thanks, Geeks!


Monday, January 6, 2014

Geeksphone Peak (Hardware Review)

This weekend I received my Geeksphone Peak, a step up from my good old ZTE Open, both Firefox OS phones. I'm very excited about this!


Mine is black on the front and white on the back. It's beautiful and fast. After shipping from Madrid, my new phone cost me $244 vs $79 for my ZTE Open.

From my point of view (Firefox OS Game Developer), the Peak is worth it! Here is the reason:


Room to move!

I now have 1.8GB for applications and 1BG for media storage. This is with no SD card installed. If I install an SD card,  the media storage bumps up to whatever my card has.

My ZTE Open only had 150MB of storage. That was fine for apps, but if I loaded a few of my own code programs (not zipped), I would run out of memory fast! Essentially I could only test one of my own apps at a time. Not good! So right now, I have about 12 times the app storage I had, so I can have lots of games and two or three of my own apps and still have room to move!

Memories are Made of This

I didn't understand what the memory meant, because everyone on Twitter told me I couldn't have 1.8GB of memory. Because I am new to phones, I didn't understand how memory works, but now I do, thanks to several helpful people.

When people talk about memory on a phone, they are talking about RAM, which is the fast memory that apps are stored in when they run, and is (probably shared) with the operating system. It turns out that even though I can't see it, my Peak has a RAM memory of 512MB. The ZTE Open only had 256MB. This memory isn't Application Storage or Media Storage. It's just memory, commonly known as RAM, and you can think of this as similar to the RAM on your computer (for example, the computer I'm typing this on says it has 9GB of RAM (64-bit Windows)) and is fairly speedy as a Windows computer.

What is so cool about my new Peak is that by having twice the RAM memory, it runs fast. I was prepared for my ZTE Open to run slow. I only paid $79 for it and I was happy that it ran at all. But it would take a minute for things to load, shut down, surf the web, etc., in its 256MB memory. But now my Peak, with 512MB of memory, is fast and isn't noticeably different from my Android Galaxy Note II or my iPhone 4.

I thought the Application Storage was RAM but it isn't. Both Application Storage and Media Storage are not RAM, they are Flash memory, similar to a USB memory stick. Not super slow, but who cares? The action is in the RAM, but being able to have 12 times the applications is really great for me. Woo, hoo!

Anything Else?

The Peak is larger. I haven't measured it, but it seems like it might be almost twice as large as the ZTE Open, though smaller than my Galaxy Note II (but larger than that tiny iPhone 4).

Oh, and an important difference. My Peak had an OS update when I turned it on the first time and right now I'm at Boot2Gecko 1.1.1.0hd-GP and I've been told that I can update this phone, unlike the ZTE Open which seemed perpetually stuck at 1.0.

This is a Peak, by the way, not the rumored Peak+.

And it was interesting to unpack it. It had a plug that looked like this

The two prongs were round and won't fit in my USA sockets, but I had a similar one that was USA standard and it had the same USB plug in the side that then I could plug in a USB cable that had a USB micro plug on the other end. 5 volts DC. It works!  No worrying about voltages. Everything is just 5 volts DC. What a wonderful world!

Everything else was standard. I plugged in a micro-SD card, plugged in a SIM card I had lying around, turned it on, answered a few standard questions, and ... Bob's your uncle, it all worked, right out of the box.


Don't Hate Me Because I'm Beautiful

I still love the ZTE Open for two reasons:

1. I will test any serious programs to make sure they run on the most-minimum platform. There are other folks out there with ZTE Opens and it is a perfect test platform.

2. Now that my Peak is my main computer, I'll risk updating the ZTE since I can afford to mess it up and take time to un-brick it later. I couldn't risk it when I wanted to keep producing this blog. I am very appreciative of the ZTE Open since it helped me to write 60+ blog posts and track down some interesting bugs with Firefox OS.

The ZTE is beautiful because it was only $79 and I could get it fast on eBay in the US. It's not like I can walk in to a phone store and buy it. The best thing I can say is that all the features work, I learned a lot about using a Firefox OS phone, it does phone calls, surfs the web, plays music, plays games! And lets me write programs in HTML5 and run them on it.

The Peak does all the same stuff, but does it faster and holds more apps. Other than that, it is the same wonderful Firefox OS, and I look forward to see what else Firefox OS will do.

I'll write more about that soon, because today (because of CES), there were announcements about more Firefox OS phones, a Firefox OS TV from Panasonic, Firefox OS tablets, and a cool Firefox OS pc that fits inside a book. It's called the APC Paper and it costs a whopping $100. Here's what it looks like from the top:


There's a PC in there and it runs Firefox OS. It's the size of a book, in case you wondered.

Here's what the back looks like:


It's got the usual USB, networking, HDMI, power, etc., I/O and reminds me a lot of the Raspberry Pi computer which is popular in the UK as a way to teach kids about computers. I have one of those too and they are cool, but not as cool as Firefox OS. Instead of Linux and Python, you can play with HTML5 inside your APC Paper!

I couldn't resist, and bought (again for $79) the innards of the APC Paper, which is called the APC Rock. (Okay, so when does the APC Scissors come out, and how far beyond that will be Lizard and Spock?)

Here's what the Rock looks like, with no case but standard I/O and the same power supply that phones use (5V).


As a retired engineer, this is a thing of beauty, especially since, unlike the Raspberry Pi, this board is designed to fit inside a standard Mini-ITX and MicroATX PC case. So I will soon have a Firefox OS PC and of course you'll be the first to hear about my adventures with this and maybe even a comparison with the Raspberry Pi.

I wouldn't necessarily recommend that you go out and buy this unless you are a hardware hacker or, on the other hand, if you've been working with the Raspberry Pi and are comfortable with those wires hanging out, give it a try. The Pi is $35, so the Rock will be approximately twice that. I'm not sure where APC is located, but there was some quick flash of VAT when I was ordering it (I didn't pay VAT, but I saw it somewhere in the background, so it might be located in the EU or who knows, these days. My guess would be that or Taiwan.)

By the way, in case you are curious, there's one other cool thing about these new APC devices besides running Firefox OS. APC was a project to create a $49 Android PC. They have one, but I have enough Androids, thank you. What is cool about this is that the design and chips for this are created by a company called VIA. You may never have heard of them, but I have, and I have a few VIA PCs lying around in a closet somewhere. You can find out more about Rock and Paper at http://apc.io/

You've heard of Intel, and you've probably heard of their rival, AMD. But there is a lesser-known Intel-compatible CPU manufacturer called VIA. And VIA owns APC. So this computer is not only a small PC, it is one that runs open source Firefox OS, open source Linux (underneath), and not-open-source but not Intel, CPU!

This is an incredible time to be working with Firefox OS. Stay tuned, but never iTuned!

Thursday, January 2, 2014

Space Fox (Game Review)

Anything with Fox in the name is worth investigating, and Space Fox is no exception. As you may have gathered from my post on Heroine Dusk, I'm an RPG game fan from way back. But I have a new interest I've been pursuing the last six months, which is space shooters. And Space Fox is definitely a space shooter!


This is a simple game, in that it doesn't have a lot of options and doesn't have music. Your white ship with orange fins is shown at the bottom left. The meteorites are orange. So is a firefox!

Here's the opening screen. You'll see it every time you crash.


The score is based on the kilometers you travel. The highest I've gotten so far is 43, but I'm sure you can do better.

There are instructions on the Marketplace page:
Discover the dark side of the space and kill all the space invaders.
- Move the ship rotating the device with the accelerometer.
- Tap the screen to shoot.
- Portrait mode only. 
The controls on this game are unusual, but very interesting for phones. I've played half-a-dozen space shooter games on the Android, but the controls were awkward and difficult to master. Most of them have little buttons that you have to press on the screen. Space Fox doesn't have any buttons. It has two basic ideas:
  1. Tilt the phone down on the left or right edge. The ship will slide in that direction. You do this to avoid the meteors. This game is in portrait mode, so it's easy to tilt side to side and learn a smooth rocking motion.
  2. Tap anywhere on the screen to shoot. If you can't avoid the meteors, you can shoot them.
That's it! The developer, Luis Jesus Maldonado Varela, probably will be adding things in the next version, but Space Fox is an interesting way to do a space shooter with controls that work for a phone. I covered the concept of tilting in my article on  Device Orientation, and the technology is fairly easy to use.

The game has a few extras. It does have sound effects for the explosions and shooting, and every once in a while if you destroy an asteroid you get something good. But the main point is that this is a different approach to space shooters, one that tries to use the new technologies of the phone!

I'll take off one point for no music and the lack of change (it's just asteroids with no extra scenery), but because this is original and has the name Fox, I give it a 4. The directions are on the Marketplace page at https://marketplace.firefox.com/app/space-fox-1.

Cost: Free
Genre: Arcade
Score: 4 (out of 5)
Tested on: ZTE Open (Firefox OS)
Get it at: Firefox Marketplace

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!