Nook In-app integration for Unity

If you are a Nook developer, chances are that you’ve heard in-app purchases are launching on the Nook this month.  This week, Nook and Fortumo made the in-app SDK for Nook available and Barnes and Noble is offering special publicity for apps using the new IAP options, if they are submitted by May 3rd.

This sounds like a great opportunity, and if you have a lot of experience creating Android apps, integrating Fortumo into your game may be trivial.  But for many users of Unity, such as myself, the process may seem daunting (it did to me!).  For my other projects, I’ve relied on third-party plugins for Unity (such as prime31‘s, which are top-notch) to do in-app purchases, display advertisements, etc.

But, assuming a Fortumo plugin is not available by May 3rd, you may want to try to integrate Fortumo’s IAP on your own. That’s what I did this week, using my usual “trial -> error -> Google -> repeat” approach.  But, using the demo project provided by Fortumo, and a number of forum posts  by Unity and Android users, I was able to piece together an integration that seems to work, and I wanted to share my approach for anyone who is interested in building their own plugin for Fortumo.

For my game, I am using the free version of Unity and the Android Basic add-on, along with Eclipse to build the plugin, and it appears to be working now (in sandbox mode).   If you have any questions (or suggestions!), please let me know, and I’m hoping to continue to improve the integration.

Set up Eclipse:

  • Register with Fortumo (http://fortumo.com/nook) and create a service (one product that you want to sell in your game).
  • Set up an Eclipse project for your Unity game.  (I made one awhile back, and used this forum post, but in the new versions of Unity, you should be able to use “Create Eclipse project” though I have not tried that myself).
  • Get the FortumoInApp-android-9.0.7.jar after you register with Fortumo and add the jar to your ./Plugins/Android/ folder in your project. Import the .jar to your Eclipse project.
  • In Eclipse, create a new Android project, and add the following  three java classes shown below (AndroidFnc.java, FortumoFnc.java, PaymentStatusReceive.java).
  • Change the package name in the java classes to your package’s name.
  • Create a jar file (AndroidFnc.jar) and save it to your ./Plugins/Android/ folder in your Unity project.

Set up your Unity project:

  • In Unity, create a gameobject to handle your IAP purchases, and attach the AndroidFnc.cs script (below).
  • In AndroidFnc.cs, replace myID and mySecret with the appropriate values from the Fortumo dashboard (http://fortumo.com/services/).
  • Modify your AndroidManifest.xml (which should be in your project’s ./Plugins/Android/ folder) with the additions shown below.  Make sure that you change the main activity from com.unity3d.player.UnityPlayerActivity to com.mypackage.name.AndroidFnc.

 Other tips:

  • For other info on integration, see http://developers.fortumo.com/, and especially the information on testing (including sample credit card numbers you can use for test purchases).

The java classes listed below are used to communicate with the UnityPlayer, to launch the IAP process, and handle the result of the purchase.  The AndroidFnc class extends UnityPlayerActivity, and we will use this class to receive requests from the game and to send information back.  AndroidFnc will launch the purchase by starting an intent for FortumoFnc (and adding the purchase parameters as extra fields to the intent).  The final class, PaymentStatusReceive, will send the result of our purchase back to Unity.

Known issues:

  • On the Nook, if a user selects Cancel in the IAP screen, the user is not automatically returned to the UnityPlayer (and needs to press the soft key back button to do so).
  • If the user is not connected to Wi-Fi, the IAP screen displays “Unknown error” with no further information (it would be better to return with a failure, I think, but I’m working on that).
  • This version does not return details of the transaction (such as the user id, or other information you could use to verify the transaction if you are also logging transactions on your own server)

AndroidFnc.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.mypackage.identifier;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;

import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;
public class AndroidFnc extends UnityPlayerActivity {
  @Override
  protected void onCreate (Bundle icicle) {
    super.onCreate (icicle);
    Log.i("AndroidFnc", "Launched");
  }
   
  public static void logUnity(String msg) {
    UnityPlayer.UnitySendMessage("androidMng", "androidMsg", msg);
  }
 
  public static void purchaseFailed() {
    Log.i("AndroidFnc", "purchase failed.");
    UnityPlayer.UnitySendMessage("androidMng", "purchaseFailed","failed");
  }
 
  public static void purchaseSuccess(String product_name) {
    Log.i("AndroidFnc", "purchase successful.");
    UnityPlayer.UnitySendMessage("androidMng", "purchaseSuccess",product_name);
  }
 
  public void buy(final String ID, final String SECRET, final String product_id, final String product_description, final boolean isConsumable) {
    UnityPlayer.UnitySendMessage("androidMng", "androidMsg", "Starting purchase.");
 
    UnityPlayer.currentActivity.runOnUiThread(new Runnable() {
 
      public void run() {
        Intent i = new Intent(getApplicationContext(), FortumoFnc.class);
        // Pass in details about our item to be purchased.
        i.putExtra("ID", ID);
        i.putExtra("SECRET", SECRET);
        i.putExtra("product_id", product_id);
        i.putExtra("product_description", product_description);
        i.putExtra("isConsumable", isConsumable);
        UnityPlayer.currentActivity.startActivity(i);
      }
    });
  }
}

FortumoFnc.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package com.mypackage.identifier;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;

import com.fortumo.android.Fortumo;
import com.fortumo.android.PaymentActivity;
import com.fortumo.android.PaymentRequestBuilder;

public class FortumoFnc extends PaymentActivity {

  // Fortumo service information - http://fortumo.com/nook
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      Log.i("FortumoFnc", "create");
    AndroidFnc.logUnity("onCreate called");
    super.onCreate(savedInstanceState);
   
    Intent intent = getIntent();
    String ID = intent.getStringExtra("ID");
    String SECRET = intent.getStringExtra("SECRET");
    String product_id = intent.getStringExtra("product_id");
    String product_description = intent.getStringExtra("product_description");
    boolean isConsumable = intent.getBooleanExtra("isConsumable", false);
   
    buy(ID , SECRET, product_id, product_description, isConsumable);
  }
 
 
  public void buy(String itemID, String appSECRET, String product_id, String product_description, boolean isConsumable) {
      Log.i("FortumoFnc", "buy");

      Fortumo.enablePaymentBroadcast(this, Manifest.permission.PAYMENT_BROADCAST_PERMISSION);
     
          PaymentRequestBuilder builder = new PaymentRequestBuilder();
          builder.setService(itemID, appSECRET);
          // displayed on receipt sent to users
          builder.setDisplayString(product_description);
          // used to restore non-consumable purchases, also available in receipt verification requests
          builder.setProductName(product_id);
          // non-consumable items can only be purchased once and purchases can be restored using the product name value
          builder.setConsumable(isConsumable);
          makePayment(builder.build());

        IntentFilter filter = new IntentFilter("com.fortumo.android.PAYMENT_STATUS_CHANGED");
        registerReceiver(updateReceiver, filter);
  }
 
  @Override
  protected void onResume() {
    super.onResume();
   
    IntentFilter filter = new IntentFilter("com.fortumo.android.PAYMENT_STATUS_CHANGED");
    registerReceiver(updateReceiver, filter);
  }
 
  @Override
  protected void onPause() {
    super.onPause();
    unregisterReceiver(updateReceiver);
  }
 
  protected void onPaymentCanceled() {
    Log.i("FortumoFnc", "cancelled");
    // Does not seem to be reached
    finish();
  }
 
  private BroadcastReceiver updateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      Log.i("FortumoFnc", "received");
      runOnUiThread(new Runnable() {
        public void run() {
          // updatePurchaseInfo();
        };
      });
      finish();
    }
  };
}

PaymentStatusReceive.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.mypackage.identifier;

import com.fortumo.android.Fortumo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

public class PaymentStatusReceiver extends BroadcastReceiver {
 
  @Override
  public void onReceive(Context context, Intent intent) {
    Bundle extras = intent.getExtras();

    if (extras.getInt("billing_status") == Fortumo.MESSAGE_STATUS_BILLED) {
      //String product_code = extras.getString("product_name");
      AndroidFnc.purchaseSuccess("success");
    }
   
    if (extras.getInt("billing_status") == Fortumo.MESSAGE_STATUS_FAILED) {
      AndroidFnc.purchaseFailed();
    }
   
  }

}

In my Unity project, I create a gameobject in my first scene to which I attach the script AndroidFnc.cs.  This gameobject will be named androidMng, and will handle communicating with my AndroidFnc.java class.

AndroidFnc.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
using UnityEngine;
using System.Collections;
using System.IO;

public class AndroidFnc : MonoBehaviour {
 
  public delegate void IAPevent(bool val);
  public static event IAPevent purchaseResult;
 
#if UNITY_ANDROID
 
  void Start() {
    GameObject androidM = GameObject.Find("androidMng");
    if (androidM == null) {  // This is the first load of the main menu
      DontDestroyOnLoad (transform.gameObject);
      this.gameObject.name = "androidMng";
    } else {
      Destroy(gameObject);
    }
  }
 
  // Used to track which purchase we are waiting to hear back about.
  public enum purchaseType {None, Coins2X , Coins5k};
  purchaseType pendingPurchase = purchaseType.None;
 
  public void getCoins(int val) {
    string ID = "";
    string SECRET = "";
   
    switch (val) {
     
    default: // 5000 coins
      pendingPurchase = purchaseType.Coins5k;
      ID = "myID";
      SECRET = "mySecret";
      break;
    }
   
    buy(ID,SECRET,val.ToString("N0") + " coins", val.ToString("N0")+ " coins", true);
  }
 
  public void get2XCoins() {   
    pendingPurchase = purchaseType.Coins2X;
    string ID = "myID";
    string SECRET = "mySecret";
   
    buy(ID,SECRET,"2X coins","2X coins",false);
  }
 
  public void buy(string ID, string SECRET, string product_id, string product_description, bool consumable) {  
    Debug.Log("Sending purchase request... " + product_id);
   
    object[] args = new object[]{ID, SECRET, product_id, product_description, consumable};
    using (AndroidJavaClass cls_AndroidFnc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) {
      using (AndroidJavaObject obj_AndroidFnc = cls_AndroidFnc.GetStatic<AndroidJavaObject>("currentActivity")) {//
                obj_AndroidFnc.Call("buy",args);
          }
    }
  }
 
  public void purchaseFailed(string val) {
    Debug.Log("purchase failed.");
    pendingPurchase = purchaseType.None;
    if (purchaseResult != null)
      purchaseResult(false);
  }
 
  public void purchaseSuccess(string val) {
     
    Debug.Log("purchase succeeded: " + val);
    // handle purchase
   
    pendingPurchase = purchaseType.None;
    if (purchaseResult != null)
      purchaseResult(true);
  }
 
  public void androidMsg(string msg) {
    Debug.Log("Android message received: " + msg);
  }
#endif
 
}

To finish up, I made the following additions to my AndroidManifest.xml (which I placed in the ./Plugins/Android/ folder):

<application android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="false">

<activity android:name="com.mypackage.identifier.AndroidFnc" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity android:name=".FortumoFnc" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:screenOrientation="landscape">
</activity>
<activity android:name="com.unity3d.player.UnityPlayerActivity" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:screenOrientation="landscape">
</activity>
<activity android:name="com.unity3d.player.UnityPlayerNativeActivity" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:screenOrientation="landscape">
<meta-data android:name="android.app.lib_name" android:value="unity" />
<meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
</activity>

<service android:name="com.fortumo.android.FortumoService" />
<service android:name="com.fortumo.android.StatusUpdateService" />
<activity android:name="com.fortumo.android.FortumoActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
<activity android:name="com.fortumo.android.PaymentActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"/>

<!-- Implement a BroadcastReceiver to track payment status -->
<!-- Should be protected with "signature" permission -->
<receiver android:name=".PaymentStatusReceiver"
android:permission="com.your.domain.PAYMENT_BROADCAST_PERMISSION">
<intent-filter>
<action android:name="com.fortumo.android.PAYMENT_STATUS_CHANGED" />
</intent-filter>
</receiver>
</application>

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<!-- Define your own permission to protect payment broadcast -->
<permission android:label="Read Fortumo payment status"
android:name="com.your.domain.PAYMENT_BROADCAST_PERMISSION"
android:protectionLevel="signature" />

<!-- "signature" permission granted automatically by system, without notifying user. -->
<uses-permission android:name="com.your.domain.PAYMENT_BROADCAST_PERMISSION" />

Nook Color, anyone?

In my last post, I mentioned that my last game, Amnesia Island, had done reasonably well on the Nook.  Over a 3 month period, the game had been downloaded over 50k times, which is good performance (in my opinion) for a game which is based on a set of memory tests for rats.

Currently, I’m working on a new game (titled Taxi Dash), which I’m hoping to release on the Nook in the next couple of weeks.  As I get closer to submitting the game to Barnes and Noble, I have become a bit concerned about how the game performs on my Android test devices.  According to my in-game counter, Taxi Dash is running at about 50 frames per second on my Samsung Player 4.0, and my first generation Kindle Fire.  But, that same version only runs at about 20 fps on my Nook Color (the original tablet released by Barnes and Noble).  And, at that frame rate, the game feels a bit laggy to me.

So, since the Nook Color is no longer sold by Barnes and Noble (though you can still get on on Amazon, ironically), I’m curious how many Nook Colors are still in use (because I don’t want to miss out on a large portion of the Nook market, and I don’t want users of the game to have a bad experience).  I haven’t found much information online on Nook device stats, so I turned to my own experience with Amnesia Island.  Of the 50k installs that Barnes and Noble reported, about 46,980 were recorded on my servers, so I would estimate that I have analytic data from most of the installations of the game.  And for each game session, I collect the device model, so I can get a sense of what types of devices/computers my players are using.

Installs of Amnesia Island received between December 20th 2012 and mid-March 2013

Installs of Amnesia Island received between December 20th 2012 and mid-March 2013

Of the sessions that were reported to my server, Continue reading

Some thoughts on IAP for the Nook

Barnes and Noble announced this week that in-app purchasing was coming to the Nook, through a partnership with Fortumo. As a parent I have enjoyed fact that the Nook does NOT have  advertisements and in-game purchases.  But, I would expect that this will be a good move for the Nook, since tablet users expect to find a wide selection of high-quality free games on mobile devices and tablets, this move should bring the Nook more in line with its competitors markets.  And, while you may not think that the Nook needs games like Subway Surfer (which uses both IAP and interstitial advertisements), that is exactly the kind of game that is not on the Nook right now, and that kids (like my own) want to play!

As a developer, I also expect that the addition of IAP is going to have an impact on the Nook marketplace, though how quickly this will happen depends on how fast new free apps are added.  In general, this will development will hurt the visibility of my own games, and I would expect, those of other small, independent game studios.  Personally, I have found the Nook to be a great market: my strongest sales have been on the Nook, as have the vast majority of downloads of my free games (or of my paid games when on a temporary sale).

For example, in December I released a new game, Amnesia Island, on the Nook.  As with all of my games, Amnesia Island was part of a research study, and in this particular study I was looking to test some navigation tasks (based on classic animal tasks such as the Barnes maze, the Morris water maze, and the 8-arm radial maze).  These were tasks that I’ve been using for some time, and which I (and my colleagues) am hoping to bring to my research on mobile platforms that I’m hoping to use over the next few years.

As I was preparing Amnesia Island, I thought that the Nook would be a good market, as I was planning to release the game for free, and was willing to forgo ads (or any monetization).  In my past few releases, I’ve been working to combine research with games that are enjoyable.  But, I knew that Amnesia Island was going to be more “research” than it was “entertainment.”  Unlike some of my recent releases, Amnesia Island is not really a game: you get points as you complete trials in each task, and your high score is tracked for each task variant, but the game is not really intended to be entertaining, as I indicated in the product description.  It was intended to let people try out virtual versions of several rat tasks that are widely used in studies of memory, and which are regularly used in human memory studies.  So, I felt it was best to release the game for free, rather than charging even a nominal amount ($0.99).  And, since there are relatively few free games on the Nook, I thought this strategy could help me obtain enough downloads to help me develop a better version of these tasks for my research studies.

Now, if I had released Amnesia Island on Google Play, or iTunes or the Amazon Appstore, I expect it would have had a few downloads, but without investing a substantial amount of money in advertising, Amnesia Island probably would have yielded less than a 1,000 total downloads on any of those platforms (based on my experience with my previous releases).  And, that at that rate, it really would not be worth my time.  But, on the Nook, Amnesia Island did much, much better.

In the three months since the game was released (from December 20th, 2012 to March 25th 2013), Barnes and Noble’s sales reports indicate that Amnesia Island was downloaded by 55,230 Nook users.  Many of these downloads came in during the first week of sales, which included the Christmas holiday in the U.S. (and 18,957 downloads were reported for December 20th through the 31st).  But, even after the holiday rush, the game has been drawing in respectable numbers: so far in March, the game has had 7,521 installs.  For a small research study, this was wonderful performance: I was able to collect data from a large sample of users in a relatively short period of time (more on that in a future post).  That is not to say that the game was well received by the users, however.  Early  user ratings of the game(in late December and early January) were polarized (with most users either giving it 1 or 5 starts), but over time the average rating has slid to 2 stars, and currently 56 of the 102 ratings logged were 1-star.  That was to be expected, given that the game is, in the end, basically a research study.  I am encouraged, though, that currently the review rated as “Most Helpful” is a 5-star review acknowledging that the app is not a game, in the sense that we might usually expect, but that the game is an interesting adaptation of classic animal memory tasks.

So, what do I think will change with Barnes and Noble’s announcement?  Well, I think that only reason Amnesia Island (a game with weak user reviews) has been able to attract +50k installs is that there are relatively few free games for the Nook.  I expect that if I had tried to release the same game after IAP gets established in the Nook market, I would have seen very few downloads.  As IAP gets off the ground, visibility in the market will change quite a bit (though, I’m curious if the lack of advertising options will continue to hold the market back), as the number of high-quality, free apps (and games) increases.

And, for the long-term viability of the Nook, this is great news.  IAP would seem to be a critical part of an Android app store (or any app store) in the current market and without it, I would expect that the future prospects for the Nook look grim (not that some are not already worried!).  But for developers, especially independent developers, the erosion of visibility on the Nook market (which is already underway simply as the number of apps released increases) is going to be greatly accelerated by IAP.

So, the end is coming, and there is no need to wait until it’s too late.  Let’s come up with some creative strategies to maintain visibility, and I’d be happy to hear your ideas (What about a homemade cross-promotional campaigns across developers, if that would be allowed by B&N?) to help us get our games in front of eyeballs.

Doodle Hangman

Recommendation: (3 out of 5) Straightforward hangman game for the Nook.
Pros: Runs well, and uses a wide range of words.
Cons: No scoring system or levels of difficulty.

Since Christmas, there have been a handful of new Nook games released (most notable among these was Temple Run: Brave, which has rapidly shot up to the top of the bestselling chart on the Nook).  I avoided the slot machine games, and what appeared to be twelve different koala-themed bubble popping games (which I did not realize was such a large genre) and picked up a copy of Doodle Hangman by Chris Martone (AppHappy Studios).

Doodle Hangman is a basic hangman game, and Martone indicates in the description that the game uses over 2,500 words in the game.  In each round of the game, you start with 8 guesses (and each incorrect guess is penalized by drawing in another piece of the doodle character.  Overall, I thought the game ran well on my Nook, and I found it to be rather challenging.  However, the app is listed in the Children’s Game category, and for ages 4+, which I would not recommend.  As a relatively literate adult, I struggled with some of the words (“whereat” for instance), and I doubt even the above average 4 year old would find such a game rewarding.  And, in the end, I think that is the biggest limitation of Doodle Hangman: it would greatly benefit from separating the words used into levels of difficulty.  For younger kids, words like cat, dog, fish, etc. could be very challenging.

Also, the game would be improved with some type of scoring system, perhaps based on the number of incorrect guesses, and the overall time required to solve each puzzle.  Or, even something as simple as keeping track of how many puzzles are solved correctly would give players a reason to struggle with each one.  All in all, I would recommend Doodle Hangman to anyone who likes word puzzle.  But, I would recommend you get it while it is on sale (currently the game is advertised as being on sale for $0.99, and is presumably going to go up to $1.99).

Colonize: Sales and other data

Colonize has been out for just under two months now, and I wanted to check in with an update on sales and other data.  Overall, the game has performed fine on Android, but it is going to take a bit longer than I originally hoped to collect enough data for our research project.  And, I was hoping to have the game out for iOS before Christmas, but after multiple rejections at Apple in November and December, the app is still under review.  Hopefully it will be out on iOS by the end of January!

When Colonize came out in November, I attempted to contact more than 50 Android game review sites.  I knew that as a game, Colonize was unlikely to be greatly successful: feedback from sympathetic playtesters had indicated that the game was too difficult to engage the average user.  But, I thought that the game’s unique features: that it was a somewhat new take on Conway’s Game of Life for mobile devices, and that it was part of an academic research project, might help get the attention of potential reviewers.

In the end, I was happy to get three reviews of Colonize in November, by AppsZoom, Playandroid.com and the G.A.M.E.S. blog.  Playandroid.com also put out a news item announcing the release of the game, and published a developer interview, all of which was very helpful in getting the word out about Colonize.

Additionally, I was able to advertise the Google Play version of the game using $50 in credit that AppsZoom provided for creating a developer account, and some credit that I had left over with Google’s Admob from a previous campaign.

With the reviews, banner advertisements, and promotion through social media, Colonize ended up with a few thousand installations through Android as of today.  Financially, this has not been enough to consider the game a financial success: I’ve seen revenue of approximately $69.56.  This breaks down into $40 through sales at Barnes and Noble, and ad revenue of about $29 through Chartboost and Appbrain.  Most of the ad revenue comes from Chartboost, as Appbrain was added only recently, after most of the installs had already occurred in Google Play.

Android Installations (2,498 total)

  • Google Play: 555 installations
  • Amazon Appstore: 79 installations
  • Barnes and Noble: 58 paid installations ($40.02), plus 1,487 free installations during a one week sale (free)  in November.
  • And, it appears that we have about 319 installations of the free trial version of Colonize on Barnes and Noble by people who have not (yet) upgraded to the full version.

So, as a commercial project, Colonize has not performed very well.  But, what about our research project?  Unfortunately, the research results do not look great either.  Of the 2,500 installations, about 1,500 have resulted in at least one data session logged on our server.  And, of the 1,5o0 installations that have provided data, most come from users who tried the game out for a few levels (mostly in the Training mode), but did not go on to complete much of the game.  In the Defense levels, which are most important for our research project, less than 100 people have completed multiple Defense levels.

But, the good news is that we have some new installations every day, and I think over a longer time-frame (a matter of months, rather than weeks) we will see enough data to start to answer our research question.  And in the meantime, I am thinking about what games to make next.  I would like to make a game that is similar to Colonize, but has a more engaging mechanic and experience, so that we can get useful data with fewer installations.  But for now, I’m focused on bringing some of my work with navigation (how people find their way through new environments) to mobile devices.

My first attempt, which I’ve called Amnesia Island, allows people to test themselves in three classic rat navigation tasks.  The game came out on the Nook in December (just before Christmas) and so far I’ve had over 12,000 installations submit data to my website (of 16,340 installations recorded by Barnes and Noble), and about 1,500 of these installations come from people have played the game far enough to provide me with some useful data.   This is much better performance than Colonize, but the main reason the game is doing well on the Nook is that I made it free, and there are still relatively few free games on the Nook (since developers cannot use in-app purchases, or use ads in free games on Barnes and Noble).  Eventually, I’d like to use the data collected from Amnesia Island to design an app that allows other researchers to use these same tasks in their own experiments, so this project is focused mostly on developing a set of research tools rather than making research games which are fun.

For our next (fun) game, keep an eye out in the summer/fall of 2013: we’ll hope to have something new ready (or at least in beta) by then!