Local flash game leaderboard tutorial

Update I’m stopping updating my whole blog and don’t have time to fix the confusing points of this post so if you get stuck there are some questions about this post answered on This StackOverflow question.

This tutorial is about how to create a local leaderboard in ActionScript 3, the principles will work on mobile in AIR or on the web. See completed project at the end of the post.

In AS3 ais used to store data to the player’s computer. In the case of a local leaderboard we want to store high score’s between games and then display them in a sorted order. Note since we’re only storing data locally ( as opposed to networked ) this will only show score’s on that machine and more complex methods would require a server component.

1. Initialize where data will be saved

Main.as 

private var m_FlashCookie:SharedObject;
private function init(e:Event = null):void
{
  //...
  m_FlashCookie = SharedObject.getLocal("LeaderboardExample");
  //...
}

2. “Play Game” and store the results of that player’s session. In the case of the example this is simply done using static variables in the Main document class.

StateGame.as 

Main.EntryScore = parseInt(m_InputBoxScore.text);
Main.EntryName = m_InputBoxName.text;

3. Fetch our saved leaderboard object of high scores. shared_object.data[“KEY_NAME”] will return null if nothing has been stored with that key.

StateLeaderboard.as

// Shared Objects store everything as untyped objects so we cast it back to an array as we will store it later
var arr:Array = Main.Inst.getSaved("TopScores") as Array;
if ( arr == null)
  arr = new Array();

//----------------------------

Main.as
public function getSaved(key:String):Object
{
  return m_FlashCookie.data.key;
}

4. Push the latest score that the last gameplay session added into the array storing the leaderboard data

StateLeaderboard.as 

// create the object that stores the data that just got created from our last gamestate
// we can add multiple stats in here if we wanted, for example "enemies killed" and "coins collected"
// in this case we just use score as an example so we have only one number to sort on
var latest_score_object:Object = {
  name: Main.EntryName,
  score: Main.EntryScore
};
// push the last score onto the list
arr.push( latest_score_object );

Note: this means that we might now have 11 scores in the array instead of the top 10.

5. Sort the leaderboard so it’s in the order we want it to be in

StateLeaderboard.as 

// sort the list from highest to lowest based on the "score" figure.
// the key here can be anything stored in the lastest_score_object entry.
arr.sortOn("score", Array.NUMERIC | Array.DESCENDING);

6. Remove extra entries in the array so we only save the “top 10”

StateLeaderboard.as 

// if adding the score from the last game made it so there were more than 10 items of the list, remove the last #11.
// since the array was sorted on the line above that means that the last score will be in the right place regardless
if ( arr.length < NUM_SCORES_SAVED )
{
  arr.pop();
}

7. Flush/Save the new leaderboard This makes it correct for next time.

StateLeaderboard.as 

// This key name must match the name we used above in step 3.
Main.Inst.saveData("TopScores", arr);

//--------------------

Main.as

// Function to store data by key.
public function saveData(key:String, dataToSave:Object):void
{
  m_FlashCookie.data.key = dataToSave;
  var flushStatus:String = null;
  try
  {
    flushStatus = m_FlashCookie.flush(10000);
  }
  catch (error:Error)
  {
    trace("Error...Could not write SharedObject to disk\n");
  }
  if (flushStatus != null)
  {
    switch (flushStatus)
    {
      case SharedObjectFlushStatus.PENDING:
        trace("Requesting permission to save object...\n");
        m_FlashCookie.addEventListener(NetStatusEvent.NET_STATUS, onFlushStatus);
        break;
      case SharedObjectFlushStatus.FLUSHED:
        trace("Value flushed to disk.\n");
      break;
      }
    }
}

8. Loop through all the leaderboard data and display it in a human readable way.

StateLeaderboard.as 

// In this example implementation we display all our data in a single textfield.
// In a real game we'd probably work with an artist to put these on seperate lines or a grid
var myHTML:String = "";
var total_stored_scores:int = arr.length;
for (var i:int = 0; i < total_stored_scores; ++i)
{
  // loop through every entry, every entry has a "name" and "score" field as that's what we save.
  var leaderboard_entry:Object = arr[i];
				
  // is this the last score that was just entered last gamestate?
  if ( leaderboard_entry == latest_score_object )
  {
    myHTML += (i+1) + ". <b><font color=\"#0002E5\">"+ leaderboard_entry.name + " " + leaderboard_entry.score +"</font></b><br>";
  }
  else
  {
    myHTML += (i+1) + ". "+ leaderboard_entry.name + " " + leaderboard_entry.score +"<br>";
  }
}
m_TF.htmlText = myHTML;

9. Rinse, repeat and observe.

DOWNLOAD EXAMPLE:
Flash Develop or Flash Pro CC project source of the complete example.

Annoyed at Google App Engine and Eclipse Indigo

Ugh… so always blog angry right?  This seems to be my pattern:

  1. Create blog for no apparent reason saying “one day I’ll update” because I happen to be doing something at the time that makes it easy. ( Getting a myspace account, when google bought blogger and was advertising like crazy, when I was setting up another SQL project on my site and saw a free wordpress install)
  2. Wait for months for something to happen tech wise that I can rant about ( that isn’t directly work related )
  3. Write an angry post or two about code problems that annoy me. Not that are difficult problems, just that shouldn’t exist as problems at all.
  4. Eventually forget password
  5. Goto: 1

We’re on step 3 now! Story time!

So I’ve just done my first install of Google App Engine to work on a text based RPG app project (More on that in future updates!)

So I install latest Eclipse (Indigo 3.7) and then happily try to install the google plug-in (found here: http://code.google.com/appengine/docs/java/tools/eclipse.html)

Which quickly leads to this error:

Cannot complete the install because of a conflicting dependency.
  Software being installed: Google Plugin for Eclipse 3.7 2.3.2.r37v201106211634 (com.google.gdt.eclipse.suite.e37.feature.feature.group 2.3.2.r37v201106211634)
  Software currently installed: WindowBuilder XML Core 1.0.0.r37x201106081533 (org.eclipse.wb.core.xml.feature.feature.group 1.0.0.r37x201106081533)
  Only one of the following can be installed at once:
    WindowBuilder Databinding XML Core 1.0.0.r37x201106161417 (org.eclipse.wb.core.databinding.xml 1.0.0.r37x201106161417)
    WindowBuilder Databinding XML Core 1.0.0.r37x201106081533 (org.eclipse.wb.core.databinding.xml 1.0.0.r37x201106081533)
  Cannot satisfy dependency:
    From: GWT Designer Editor 2.3.2.r37x201106201351 (com.google.gdt.eclipse.designer.editor.feature.feature.group 2.3.2.r37x201106201351)
    To: org.eclipse.wb.core.xml.feature.feature.group 1.0.0.r37x201106161417
  Cannot satisfy dependency:
    From: Google Plugin for Eclipse 3.7 2.3.2.r37v201106211634 (com.google.gdt.eclipse.suite.e37.feature.feature.group 2.3.2.r37v201106211634)
    To: com.google.gdt.eclipse.designer.editor.feature.feature.group 2.2.0
  Cannot satisfy dependency:
    From: WindowBuilder XML Core 1.0.0.r37x201106081533 (org.eclipse.wb.core.xml.feature.feature.group 1.0.0.r37x201106081533)
    To: org.eclipse.wb.core.databinding.xml [1.0.0.r37x201106081533]
  Cannot satisfy dependency:
    From: WindowBuilder XML Core 1.0.0.r37x201106161417 (org.eclipse.wb.core.xml.feature.feature.group 1.0.0.r37x201106161417)
    To: org.eclipse.wb.core.databinding.xml [1.0.0.r37x201106161417]

Ruh-roh, more time on the internet leads me to a bug in Eclipse’s database. But of course the work around doesn’t work for me there, something else must of changed since that was posted. So I need to dig through the PAIN that is getting individual updates in eclipse, which I hate digging for.

At least for me the only work around I got to work when installing Google App Engine on a fresh install was:

  1. Fail and spend way more time looking around the internet than installing something should take.
  2. Help -> Install New Software from “http://download.eclipse.org/releases/indigo”
  3. Select all things “WindowBuilder” related.
  4. Follow instructions on google tutorial ( install from “http://dl.google.com/eclipse/plugin/3.7”)
  5. PROFIT! ( probably not.)

There are some similar workarounds on posts after googling this error, but that first link is difficult to find for someone who hasn’t worked in eclipse in a few years and “Update” of course does nothing.