Using Google Play Games on the Web

As many of you know, I now work for Google on the Play Games Team. We provide APIs for game developers, implementing useful features like leaderboards and achievements, so the developer doesn't have to. While many Android developers are using our services, adoption on the web could be better, so lets take a look at how to integrate the Google Play Games Services achievements into a web game.

Getting ready

Become a Google developer and have added the game to the Developer Console. I've done this with my Snake game:

Add Game Screen

Link the game to at least one web URL:

Add Achievement Screen

Create a couple of basic achievements for your application:

Add Achievement Screen

Set your Google+ email up as a trusted tester (or publish your game so anyone can log in):

Testing Screen

Here is the achievement setup screen:

Testing Screen

If you have an incremental achievement, check the optional box (I recommend testing one incremental and one non-incremental):

Testing Screen

How do it…

To use play services, players must first authenticate with G+[2]. For the simplest method, include the following in the header of the page:

<meta name="google-signin-clientid" content="YOUR_CLIENT_ID_HERE" />
<meta name="google-signin-cookiepolicy" content="single_host_origin" />
<meta name="google-signin-approvalprompt" content="auto" />
<meta name="google-signin-callback" content="YOUR_JS_CALLBACK_FUNCTION" />
<meta name="google-signin-scope" content="https://www.googleapis.com/auth/games" />

And the G+ button:

<span id="signinButton"><span class="g-signin"></span></span>

And the necessary G+ JavaScript:

<script type="text/javascript">
    (function() {
        var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
        po.src = 'https://apis.google.com/js/client:plusone.js';
        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
    })();
</script>

This will load the G+ script, show the login button, and if the user clicks on the login button, authenticate players to use the Games services. When they authenticate G+ will call the JavaScript function specified by google-signin-callback:

function signinCallback(authResult) {
    if (authResult['status']['signed_in']) {
      document.getElementById('signinButton').style.display = 'none';
      // Safe to use API here (gapi.client.games).
    } else {
      // Update the app to reflect a signed out user
      // Possible error values:
      //   "user_signed_out" - User is signed-out
      //   "access_denied" - User denied access to your app
      //   "immediate_failed" - Could not automatically log in the user
      console.log('Sign-in state: ' + authResult['error']);
    }
  };

Once authenticated you can begin to use the Games API[3]. To fetch and store a list of the achievement definitions:

var oAchievementDefinitions = {};
gapi.client.games.achievementDefinitions.list().execute(function(oResponse) {
    var aItems = oResponse.items || [];
    for (var i = 0, j = aItems.length; i < j; i++) {
        oAchievementDefinitions[aItems[i].id] = aItems[i];
    }
});

Before calling APIs on behalf of the player, fetch the player object for the authenticated user:

gapi.client.games.players.get({playerId: 'me'}).execute(function(oPlayer) {
  // Use the player to make API calls here, oPlayer.playerId
});

To fetch a player's achievement progress:

gapi.client.games.achievements.list(
        {forceRefresh: true, playerId: oPlayer.playerId})
    .execute(function(oResponse) {
        // oResponse.items will have the state and player progress for each definition
    });

To complete an achievement:

gapi.client.games.achievements.unlock({achievementId: 'ID_OF_ACHIEVEMENT'})
    .execute(function(oResponse) {
        if (oResponse.newlyUnlocked) {
            // First time the achievement unlocked, show something in the UI
        }
    });

To increment an achievement:

gapi.client.games.achievements.increment(
        {achievementId: 'ID_OF_ACHIEVEMENT', stepsToIncrement: 1}))
    .execute(function(oResponse) {
        if (oResponse.newlyUnlocked) {
            // First time the achievement unlocked, show something in the UI
        }
    });

How it works…

This is a dense article and mostly everything is shown through examples above, so I will keep the writeup brief. The first step is to become a developer on Google[1] and use the console to create the artifacts for your game. It’s pretty straight forward, but will cost a one-time fee of $20.

The two tricky parts to setup are linking an app to a game and setting up trusted testers, if you do not publish the game making it public. For the purposes of a web game, linking an app means entering the URL for the game. Each URL will have its own entry and therefore its own client ID (which goes in the header meta information). You can have any number of linked apps, so have at least one for production and one for development. If you have trouble authenticating G+, make sure the URLs are correct and that you are using the right client ID. Trusted testers are the email address of people who can authenticate against your game, even if the game isn’t published yet. These emails should be the G+ account of testers, and allows developers to authenticate before the app is publicly available.

Unfortunately, since Google Play Games Services is a Google product, it currently only uses G+ for authentication. I think this is limiting, but hopefully a better authentication story can be found in the future. Once, the user authenticates you need to create/fetch a player ID for them from the Games service (shown above). You will have a limited amount of information about the player on the player object, but more importantly can now start calling Games services APIs for your game on the player’s behalf.

The Games services API endpoints are a lot like database tables with definitions and instances. For achievements there is the list of achievement definitions (achievementDefinitions.list()), which are unique per game, and a list of achievement instances (achievements.list()), which are unique per player. The achievement instances reference the achievement definition ID and must be mapped together in your code to properly indicate the state of an achievement for the current player. Incrementing, setting, revealing, or unlocking an achievement are all calls that the developer makes against the API to indicate the player’s current progress in the game.

To see a working web implementation, see version 3 of my Snake game.

I have shown how to work with Achievements, but leaderboards and turn-based multiplayer work much the same. Additionally, once you adopt our services, you have already done the hard work and will be ready for new features which we are frequently adding to the API.

Currently, all APIs are REST and the only optimizations built into the APIs are URL caching through headers. I have been playing with automatic client-side storage of GET requests, but there is a lot of room for improvement. Additionally, it would be cool to build a more developer-friendly wrapper around the REST API to increase adoption. If anybody takes this task up, feel free to reach out to me for reviews and help.

References

  1. Google Developer Console
  2. G+ Client Setup
  3. Play Games API Reference

Site Outage Fixed - Down for 32 hours :(

I apologize that the site has been down for a couple of days. It was a perfect storm of events. For starters, Amazon told me about two weeks ago that my server was going to be terminated and that I should do something about it (they do this now and again, as they upgrade equipment). And like any good developer, I was procrastinating until the last minute (Wednesday this week). Then on Tuesday, I received ...

Event Bubble & Capture Phases

One of the less understood, but powerful feature of browser events are their phases. According to the W3C level 2 spec there are three phases[1]: AT_TARGET=2, BUBBLING_PHASE=3, and CAPTURING_PHASE=1. Most browsers also implement a fourth phase[2]: NONE=0.

Getting ready

Just a quick note that everything discussed in this article is for modern browsers (all browsers except IE <9). Prior to IE 9, Internet Explorer used its own event system, instead of conforming ...

Passing Objects into addEventListener Instead of Functions

I was reviewing the browser event stack the other day and was reminded of a rarely used feature of addEventListener that allows developers to autobind the execution context object, instead of requiring a call to bind or using a library, that is worth sharing, if you weren’t already aware.

How do it…

Typically, when attaching an event, we write:
 var myObj = { handleEvent: function (evt) { // 'this' will be scoped ...

Running Android Tests on a Device or Emulator

I have not been doing much web development lately, so its been difficult to come with interesting topics. However, I have been doing a lot of android development and since many engineers have to work cross discipline, I think an android article be relevant. This article will discuss how to run unit tests against your android code, directly on the android device or emulator.

Getting ready

You will need to install the

Cherry-Picking for Fun and Profit

In Git, it is often useful to merge one specific commit from one branch into another. Frequently this happens when Using Git Interactive Rebase With Feature Branches, as you develop in the branch, you realize that one or more of your commits should be added to master right away, but not all the CLs. Enter git cherry-pick <changelist hash> for the win! The cherry pick command allows you to merge one CL from a ...

Gaming Engine - Snake Demo v2

Last week I was busy at GDC and have not had time to put together a detailed article, so in the spirit of GDC, I thought I would share the latest iteration of my HTML5 gaming engine (still very rough). There has been a lot of progress around the Game class to support stages (or levels) and a score board to track the player’s score. The stages are demoed by a new version ...

Use && Instead of Semicolon to Separate Commands

Today’s article will be short and will cover a bash topic that frustrates me to no end. Please don’t use ; to separate commands, when you mean &&. There is an important difference between the two and many developers never realize that they want to be using && in their scripts.

How do it…

Here is a common oneliner that you might use to compile a package:
 ./configure ; make ; make ...

Using Promises to Cache Static AJAX JSON Data

This article showcases a useful caching strategy for static data that is fetch via AJAX. We will use jQuery to setup a promise and cache the data in the localStorage for subsequent page loads or data loads.

Getting ready

A modern web browser supporting localStorage and JSON. Also, a basic understanding of promises[2] is helpful.

How do it…

Here is the code:
 (function($) { var oKeyDeferredMap = {}; function fnReadData(sKey) ...

Joined Google Play Games

I must apologize for the dearth of articles these last couple of weeks. As some of you know, I recently joined Google and there is a lot of technology to come up to speed on. Specifically, I have joined the Google Play Games team, which is a core service of the android operating system. We provide APIs to help game developers build better games with less work, and I am super excited to ...