Analytics, Level sharing, Playtomic.Leaderboards and more for Android games!
Current as of 11/20/2011. If you see or have any problems let us know!
Download it: playtomic-mono-android-0.5.zip, or get it from GitHub
Copy the Playtomic folder and everything in it to your game's folder.
Before you do anything else you must initialize the API using your credentials from the dashboard. Once you have done that, you can log the view when the player opens your game or resumes it.
To initialize the Playtomic API you need to get a reference to an object of the class Playtomic an save it in a member variable of your Application class. For an explanation of the Application object an its life cicle you can read Android Application class
public class TestApp : Application { // we need a reference to the Playtomic API // private Playtomic playtomic = null; public override void OnCreate() { base.OnCreate(); // get a reference to the singleton Playtomic class // // Get your credentials from the Playtomic dashboard (add or select game then go to API page) // playtomic = Playtomic.GetInstance( /*replace with gameId*/, /*replace with gameGuid*/, /*replace with apikey*/, this); Playtomic.Log.View(); } }
A view occurs whenever somebody views your game. This should go somewhere very early in your code, like after you get a reference to the singleton Playtomic class.
public class TestApp : Application { // we need a reference to the Playtomic API // private Playtomic playtomic = null; public override void OnCreate() { base.OnCreate(); // get a reference to the singleton Playtomic class // // Get your credentials from the Playtomic dashboard (add or select game then go to API page) // playtomic = Playtomic.GetInstance(/*replace with gameId*/, /*replace with gameGuid*/, this); // logging a view event // Playtomic.Log.View(); } }
A play occurs when someone begins a game by clicking your play button or whatever action is relevant to your game. A person can get between 0 and many plays during a single view.
They're tracked seperately because the main menu is the first thing the player sees after loading and splash animations, and if they don't like it they'll leave.
This data is logged automatically when you send other events.
private void StartedGame() { Playtomic.Log.Play();; // continue starting game ...
Events are sent in batches each time the play timer updates (every 30 seconds after the first minute). If you want to ensure an event gets sent:
Playtomic.Log.ForceSend();
Some games are very resource-intensive and the API might send off a batch of events at exactly the wrong time. You can freeze and unfreeze the logging at any time by:
Playtomic.Log.Freeze(); Playtomic.Log.Unfreeze();
When logging is frozen all events are queued but not sent until you unfreeze the API.
You must add a call to freeze in the method OnPause() of your Activities to let the Playtomic API stop the timer when your activity is becoming inactive and consequently you must add a call to unfreeze in the method OnResume() to let the Playtomic API restart the timer.
protected override void OnPause() { Playtomic.Log.Freeze(); base.OnPause(); } protected override void OnResume() { Playtomic.Log.Unfreeze(); base.OnResume(); }
When a connection to internet is not active all log are saved to be sent later. The maximum size of this cache is 1 MB. You can change it to a lower value using the method OfflineQueueMaxSize.
public static int OfflineQueueMaxSize
This cache persists even when your game is closed. The log will be sent the next time your game runs and internet is active.
Custom metrics allow you to track how many people do something in your game. For instance, how many play on easy, medium or hard, or how many play in English vs. Spanish, or how many view the tutorial or skip it. Anything you think can help you improve your game can be defined in custom metrics.
You can define custom metrics directly in your game and they will be added to Playtomic automatically. Groups can be automatically assigned via an optional second parameter or set up later in the dashboard.
You can also limit custom metrics to unique-per-view occurances with a third parameter.
Playtomic.Log.CustomMetric("ViewedCredits", null, false); // metric, names must be alphanumeric Playtomic.Log.CustomMetric("Credits", "Screens", false); // metric in a group, groups must be alphanumeric Playtomic.Log.CustomMetric("ClickedLink", "Links", true); // unique metric with group
Level metrics track events on a per-level basis so you can drill down into your difficulty and retention by identifying which levels have problems and what those problems are.
There are three types of level metrics - counters (like custom metrics), ranged-value and average-value.
Note that you can pass either an integer level number or a string name of the level. If your game is not using numeric levels (eg an escape game) then you would pass the name of each screen / area as a level.
You can define level metrics directly in your game and they will be added to Playtomic automatically.
Level metrics support unique-per-play occurrances via an optional second parameter. If the player starts a new game they will be tracked again.
These metrics track how many times something occurs in your levels, for instance deaths and restarts.
One of the most valuable pieces of data you can track is how many people begin each level, this allows you to see where you lose players.
Playtomic.Log.LevelCounterMetric("Began", "name", false); // level names must be alphanumeric Playtomic.Log.LevelCounterMetric("Restarts", 1, false); // level numbers are integers
These metrics track the average of something in your levels, for instance the average time to finish a level or the average number of retries. It also tracks the minimum and maximums.
Playtomic.Log.LevelAverageMetric("metricName", "levelName", 100, true); Playtomic.Log.LevelAverageMetric("metricName", 1, 100, true);
These metrics track metrics with values, for instance in a golf game you might track how many shots it takes to complete each level, or you might track the % of coins collected on each level.
Playtomic.Log.LevelRangedMetric("Shots", "field", 10, false); Playtomic.Log.LevelRangedMetric("PercentCoinsCollected", 1, 78, false);
Heatmaps allow you to map activity (clicks, deaths, first deaths, or anything else you want) against an image you upload in the dashboard.
Playtomic.Log.Heatmap("metric", "Heatmap", 10, 50);
In the dashboard you upload a background image for the Heatmap, and then it is shared by any metrics using it.
Link tracking allows you to keep track of how many people open URLs in your game, providing you information on unique and total clicks that can be fully audited to allow you to identify good sources of traffic.
Link tracking does not change your URL or redirect traffic through a different url!
You track a link just by passing a URL and some other information to the API.
PlaytomicLink link = new PlaytomicLink(); link.Track("http://armorgames.com/", "armorgames", "sponsor");
When you track a link it automatically also tracks the totals for the domain in a group it creates called DomainTotals. The DomainTotals allows you to see how many unique, total and failed clicks occurred for a single domain even if you have multiple, different links to it (eg walkthrough or differently-structured sponsor links).
Android users can use Parse directly through their own Android SDK.
You can do pretty much anything you want with a custom database, including:
The level sharing API provides a way to store and retrieve user-generated content for your game. It can operate anonymously or authenticated via any 3rd party service you're already using.
Saving and listing levels uses this class to represent a level.
| Property | Type | Accessor | Description |
|---|---|---|---|
| playerName | String | PlayerName | The name of the player (or "anonymous", "guest", etc), or the name provided by any 3rd party API. |
| playerId | String | PlayerId | If you're working under a 3rd party API you can include the player's user id |
| playerSource | String | PlayerSource | If you're working under a 3rd party API you can specify which, eg "gamersafe" or "mochicoins" |
| name | String | Name | The name of the level |
| data | String | Data | The data for the level. You can Base 64 encode a ByteArray to a string if necessary. |
| votes | int | Votes | The number of votes the level has |
| score | int | Score | The sum of all votes the level has |
| plays | int | Plays | The number of plays the level has |
| rating | double | Rating | The rating the level has (score / votes) |
| date | DateTime | Date | The date of the level, determined automatically by Playtomic |
| relativeDate | String | RelativeDate | The relative date of the level eg "7 minutes ago", determined automatically by Playtomic |
| customData | Dictionary<String, String> | CustomData | Any additional data you want to (or have) attached to a level. |
| String | ThumbnailUrl | Returns the URL of a thumbnail. | |
| Object | Thumbnail | Returns the thumbnail if you included them when listing. | |
| String | GetCustomValue | Retrieves a custom property. | |
| String | AddCustomValue | Adds a custom property. |
All methods are asynchronous. To get a response from this methods the caller must implement the interface PlaytomicRequestListener.
// create a new PlaytomicPlayerLevels object // PlaytomicPlayerLevels playerLevels = new PlaytomicPlayerLevels (); // we need to add a delegate // playerLevels.OnRequestFinished = delegate (Object sender, PlaytomicResponse<PlaytomicLevel> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestPlayerLevelsSaveFinished (playtomicResponse.Data); } else { // we call a function for failed cases // RequestPlayerLevelsSaveFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // save a level // playerLevels.Save (level);
| Parameter | Type | Description |
|---|---|---|
| level | PlaytomicLevel | An instance of PlaytomicLevel holding the level data |
Example saving level:
private void LevelSave () { L.Log ("\nLevel Save", this); // for this example we create a random name using the Random object // Random generator = new Random (); int r = generator.Next (); PlaytomicLevel level = new PlaytomicLevel ("level name " + Math.Abs (r % 100), "ben4", "0", "r=-152&i0=13,440,140&i1=24,440,140&i2=25,440,140&i3=37,440,140,ie,37,450,150"); // create a new PlaytomicPlayerLevels object // PlaytomicPlayerLevels playerLevels = new PlaytomicPlayerLevels (); // we need to add a delegate // playerLevels.OnRequestFinished = delegate (Object sender, PlaytomicResponse<PlaytomicLevel> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestPlayerLevelsSaveFinished (playtomicResponse.Data); } else { // we call a function for failed cases // RequestPlayerLevelsSaveFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // save a level // playerLevels.Save (level); } private void RequestPlayerLevelsSaveFinished (List<PlaytomicLevel> data) { L.Log ("PlayerLevels Save", this); foreach (PlaytomicLevel level in data) { mLevelId = level.LevelId; L.Log ("Level:\nLevel Id=\"" + mLevelId + "\"", this); } } private void RequestPlayerLevelsSaveFailed (int errorCode, String message) { L.Log ("PlayerLevels Save failed to save because of errorcode #" + errorCode + " - Message:" + message, this); }
Levels can be rated 1 - 10 by players. Rating can be done anonymously with some protection against repeat voting, or bound to PlayerIds if you specify them.
// create a new PlaytomicPlayerLevels object // PlaytomicPlayerLevels playerLevels = new PlaytomicPlayerLevels (); playerLevels.OnRequestFinished = delegate (Object sender, PlaytomicResponse<PlaytomicLevel> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestPlayerLevelsRateFinished (); } else { // we call a function for failed cases // RequestPlayerLevelsRateFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // rate a level playerLevels.Rate (mLevelId, 8);
| Parameter | Type | Description |
|---|---|---|
| levelid | String | A level id, which you can retrieve via [level getLevelId] |
| rating | int | 1 - 10 |
Example rating level:
private void LevelRate () { L.Log ("\nLevel Rate", this); // create a new PlaytomicPlayerLevels object // PlaytomicPlayerLevels playerLevels = new PlaytomicPlayerLevels (); playerLevels.OnRequestFinished = delegate (Object sender, PlaytomicResponse<PlaytomicLevel> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestPlayerLevelsRateFinished (); } else { // we call a function for failed cases // RequestPlayerLevelsRateFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // rate a level playerLevels.Rate (mLevelId, 8); } private void RequestPlayerLevelsRateFinished () { L.Log ("Rate level success", this); } private void RequestPlayerLevelsRateFailed (int errorCode, String message) { L.Log ("PlayerLevels Rate failed to rate because of errorcode #" + errorCode + " - Message:" + message, this); }
Listing levels can be done by popular or newest, with optional filtering by date ranges and/or custom Playtomic.Data.
public void List( String mode, int page, int perPage, Boolean includeData, Boolean includeThumbs, Dictionary<String, String> customFilter) public void List( String mode, int page, int perPage, Boolean includeData, Boolean includeThumbs, Dictionary<String, String> customFilter, DateTime dateMin, DateTime dateMax)
| Parameter | Type | Description |
|---|---|---|
| mode | String | popular or newest |
| andPage: | int | 1, or determine it yourself |
| andPerPage: | int | Number of levels to return |
| andIncludeData | Boolean | Return the level data with the lists. This lets you go directly into levels without requesting them individually, but if you are displaying a large list there will be less data to transmit without it. |
| andIncludeThumbs | Boolean | Returns Base64'd strings of the PNG thumbnails if they're provided. You may not use thumbnails, or you may generate them directly from the data. |
| andCustomFilter | Dictionary<String, String> | Filter levels based on custom data you stored with them (eg theme or anything else). |
| andDateMin | DateTime | The minimum creation date, eg if you wanted popular levels made this week. |
| andDateMax | DateTime | The maximum creation date, eg if you wanted popular levels made last month. |
An example listing levels:
private void LevelList () { L.Log ("\nLevel List", this); // create a new PlaytomicPlayerLevels object // PlaytomicPlayerLevels playerLevels = new PlaytomicPlayerLevels (); playerLevels.OnRequestFinished = delegate (Object sender, PlaytomicResponse<PlaytomicLevel> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestPlayerLevelsListFinished (playtomicResponse.Data); } else { // we call a function for failed cases // RequestPlayerLevelsListFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; playerLevels.List ("popular", 1, 10, false, false, null); } private void RequestPlayerLevelsListFinished (List<PlaytomicLevel> data) { L.Log ("PlayerLevels {", this); ShowLevels (data); } private void RequestPlayerLevelsListFailed (int errorCode, String message) { L.Log ("PlayerLevels List failed to list because of errorcode #" + errorCode + " - Message:" + message, this); } private void ShowLevels (List<PlaytomicLevel> data) { foreach (PlaytomicLevel level in data) { L.Log ("----------------------------------\nLevel:\nName=\"" + level.Name + "\"", this); L.Log ("Level Id=\"" + level.LevelId + "\"", this); L.Log ("Player Name=\"" + level.PlayerName + "\"", this); L.Log ("Player Source=\"" + level.PlayerSource + "\"", this); L.Log ("Date=\"" + level.Date + "\"", this); L.Log ("Relative Date=\"" + level.RelativeDate + "\"", this); L.Log ("Data=\"" + level.Data + "\"", this); L.Log ("Votes=\"" + level.Votes + "\"", this); L.Log ("Plays=\"" + level.Plays + "\"", this); L.Log ("Rating=\"" + level.Rating + "\"", this); L.Log ("Score=\"" + level.Score + "\"", this); L.Log ("Custom Data {", this); foreach (KeyValuePair<String, String> entry in level.CustomData) { L.Log ("Var: Name=\"" + entry.Key + "\" Value=\"" + entry.Value + "\"", this); } L.Log ("}", this); } L.Log ("}", this); }
If you do not include the data when you load lists of levels then you can request it seperately:
(public void Load(String levelId)
| Parameter | Type | Description |
|---|---|---|
| levelId | String | level.LevelId |
An example loading a single level
private void LevelLoad () { L.Log ("\nLevel Load", this); // create a new PlaytomicPlayerLevels object // PlaytomicPlayerLevels playerLevels = new PlaytomicPlayerLevels (); playerLevels.OnRequestFinished = delegate (Object sender, PlaytomicResponse<PlaytomicLevel> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestPlayerLevelsLoadFinished (playtomicResponse.Data); } else { // we call a function for failed cases // RequestPlayerLevelsLoadFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; playerLevels.Load (mLevelId); } private void RequestPlayerLevelsLoadFinished (List<PlaytomicLevel> data) { L.Log ("PlayerLevels {", this); ShowLevels (data); } private void RequestPlayerLevelsLoadFailed (int errorCode, String message) { L.Log ("PlayerLevels Load failed to load because of errorcode #" + errorCode + " - Message:" + message, this); }
The leaderboards API gives you very flexible high and low score Playtomic.Leaderboards. They can be created in your game dynamically or set up in the edit leaderboards page.
The leaderboards use the PlaytomicScore object for representing the players' scores.
| Property | Type | Accessor | Description |
|---|---|---|---|
| name | String | Name | The player name. This can be by the player or provided by any 3rd party |
| points | int | Points | The player's score |
| rank | int | Rank | The player's rank based on the listing criteria you use. |
| date | DateTime | Date | The date of the score, determined automatically by Playtomic |
| relativeDate | String | RelativeDate | The relative date of the score eg "7 minutes ago", determined automatically by Playtomic |
| customData | Dictionary<String, String> | CustomData | Any additional data you want to (or have) attached to a score, like the level the player reached or what character they used |
| String | GetCustomValue | Retrieves a custom property. | |
| String | AddCustomValue | Adds a custom property. |
All methods are asynchronous. To get a response from this methods the caller must implement the interface PlaytomicRequestListener.
Score submission is handled by:
// create a new PlaytomicLeaderboards object // PlaytomicLeaderboards leaderboards = new PlaytomicLeaderboards (); // we need to set a delegate // leaderboards.OnRequestFinished = delegate (Object sender, PlaytomicResponse<PlaytomicScore> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestLeaderBoardSaveFinished (); } else { // we call a function for failed cases // RequestLeaderBoardSaveFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // create a new score // PlaytomicScore score = new PlaytomicScore (/* Constructor parameters */); Dictionary<String, String> customData = score.CustomData; customData.Add ("cd1", "value1"); customData.Add ("cd2", "value2"); customData.Add ("cd3", "value3"); // save a score // leaderboards.Save ("High scores", score, true, true);
| Parameter | Type | Description |
|---|---|---|
| table | String | The score table to submit to, alphanumeric |
| score | PlaytomicScore | An instance of PlayerScore which contains score information |
| highest | Boolean | Leaderboard tables can be created dynamically from within your game so you specify the mode. |
| allowduplicates | Boolean | If you don't allow duplicates new, worse scores will not be saved by a player. |
An example submitting an score
private void LeaderboardSave () { L.Log ("\nLeaderboard Save", this); // create a new PlaytomicLeaderboards object // PlaytomicLeaderboards leaderboards = new PlaytomicLeaderboards (); // we need to set a delegate // leaderboards.OnRequestFinished = delegate (Object sender, PlaytomicResponse<PlaytomicScore> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestLeaderBoardSaveFinished (); } else { // we call a function for failed cases // RequestLeaderBoardSaveFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // create a new score // PlaytomicScore score = new PlaytomicScore ("Ben", 2000000); Dictionary<String, String> customData = score.CustomData; customData.Add ("cd1", "value1"); customData.Add ("cd2", "value2"); customData.Add ("cd3", "value3"); // save a score // leaderboards.Save ("High scores", score, true, true); } private void RequestLeaderBoardSaveFinished () { L.Log ("Save score success", this); } private void RequestLeaderBoardSaveFailed (int errorCode, String message) { L.Log ("Leaderboard save failed to save because of errorcode #" + errorCode + " - Message:" + message, this); }
Scores are loaded via a simple method that returns an array of PlayerScore objects to your function where you can display the data in your leaderboard.
// create a new PlaytomicLeaderboards object // PlaytomicLeaderboards leaderboards = new PlaytomicLeaderboards (); // we need to set a delegate // leaderboards.OnRequestFinished = delegate (Object sender, PlaytomicResponse<PlaytomicScore> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestLeaderBoardListFinished (playtomicResponse.Data); } else { // we call a function for failed cases // RequestLeaderBoardListFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // list a score // leaderboards.List ("High scores", true, "alltime", 1, 20, null);
| Parameter | Type | Description |
|---|---|---|
| table | String | Your leaderboard table name |
| highest | Boolean | If the table does not exist it will be created with this mode. |
| mode | String |
The list mode can return scores from:
|
An example showing scores
private void LeaderBoardList () { L.Log ("\nLeaderboard List", this); // create a new PlaytomicLeaderboards object // PlaytomicLeaderboards leaderboards = new PlaytomicLeaderboards (); // we need to set a delegate // leaderboards.OnRequestFinished = delegate (Object sender, PlaytomicResponse<PlaytomicScore> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestLeaderBoardListFinished (playtomicResponse.Data); } else { // we call a function for failed cases // RequestLeaderBoardListFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // list a score // leaderboards.List ("High scores", true, "alltime", 1, 20, null); } private void RequestLeaderBoardListFinished (List<PlaytomicScore> data) { L.Log ("Leaderboard {", this); foreach (PlaytomicScore score in data) { L.Log ("----------------------------------\nScore:\nName=\"" + score.Name + "\"", this); L.Log ("Points=\"" + score.Points + "\"", this); L.Log ("Date=\"" + score.Date + "\"", this); L.Log ("Relative Date=\"" + score.RelativeDate + "\"", this); L.Log ("Rank=\"" + score.Rank + "\"", this); L.Log ("Custom Data {", this); foreach (KeyValuePair<String, String> entry in score.CustomData) { L.Log ("Var: Name=\"" + entry.Key + "\" Value=\"" + entry.Value + "\"", this); } L.Log ("}", this); } L.Log ("}", this); } private void RequestLeaderBoardListFailed (int errorCode, String message) { L.Log ("Leaderboard list failed to list because of errorcode #" + errorCode + " - Message:" + message, this); }
You can now submit scores and at the same time return the leaderboard page that that score is on.
This combines the Save and List approaches from above:
// create a new PlaytomicLeaderboards object // PlaytomicLeaderboards leaderboards = new PlaytomicLeaderboards (); // we need to set a delegate // leaderboards.OnRequestFinished = delegate (Object sender, PlaytomicResponse<PlaytomicScore> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestLeaderBoardListFinished (playtomicResponse.Data); } else { // we call a function for failed cases // RequestLeaderBoardSaveFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; PlaytomicScore score = new PlaytomicScore (/* Constructor parameters*/); Dictionary<String, String> customData = score.CustomData; customData.Add ("cd1", "value1"); customData.Add ("cd2", "value2"); customData.Add ("cd3", "value3"); // save and list a score // leaderboards.SaveAndList ("High scores", score, true, true, "alltime", 20, null, true, null);
Some important notes:
Scores are no longer available directly via URL as they expect POST data now. You will need to use the HTML5 / JavaScript API for showing scores on your web page, or the Flash or other APIs for embedding them in a SWF or other container.
You can now provide your players the ability to create their own leaderboard complete with shortened URL they can give their friends to compete against each other.
Creating a leaderboard is simply:
// create a new PlaytomicLeaderboards object // PlaytomicLeaderboards leaderboards = new PlaytomicLeaderboards (); // we need to set a delegate // leaderboards.OnRequestPrivateLeaderboardFinished = delegate (Object sender, PlaytomicResponse<PlaytomicPrivateLeaderboard> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestPrivateLeaderBoardSaveFinished (playtomicResponse.GetObject ()); } else { // we call a function for failed cases // RequestPrivateLeaderBoardSaveFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // create a private leaderboard // leaderboards.CreatePrivateLeaderboard ("Android Test", true);
| Parameter | Type | Description |
|---|---|---|
| table | String | Your private leaderboard table name |
| highest | Boolean | The table will be created with this mode. |
An example creating a private leaderboard
private void PrivateLeaderboardSave () { L.Log ("\nPrivate Leaderboard Create", this); // create a new PlaytomicLeaderboards object // PlaytomicLeaderboards leaderboards = new PlaytomicLeaderboards (); // we need to set a delegate // leaderboards.OnRequestPrivateLeaderboardFinished = delegate (Object sender, PlaytomicResponse<PlaytomicPrivateLeaderboard> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestPrivateLeaderBoardSaveFinished (playtomicResponse.GetObject ()); } else { // we call a function for failed cases // RequestPrivateLeaderBoardSaveFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // create a private leaderboard // leaderboards.CreatePrivateLeaderboard ("Android Test", true); } private void RequestPrivateLeaderBoardSaveFinished (PlaytomicPrivateLeaderboard leaderboard) { mBitly = leaderboard.Bitly; L.Log ("Private Leaderboard {", this); L.Log ("name = " + leaderboard.Name, this); L.Log ("tableId = " + leaderboard.TableId, this); L.Log ("bitly = " + leaderboard.Bitly, this); L.Log ("permalink = " + leaderboard.Permalink, this); L.Log ("highest = " + (leaderboard.Highest ? "yes" : "no"), this); L.Log ("realName = " + leaderboard.RealName, this); L.Log ("}", this); } private void RequestPrivateLeaderBoardSaveFailed (int errorCode, String message) { L.Log ("Leaderboard create failed because of errorcode #" + errorCode + " - Message:" + message, this); }
When a person plays your game you can ask he or she for the bitly code to load a private leaderboard by:
// create a new PlaytomicLeaderboards object // PlaytomicLeaderboards leaderboards = new PlaytomicLeaderboards (); // we need to set a delegate // leaderboards.OnRequestPrivateLeaderboardFinished = delegate (Object sender, PlaytomicResponse<PlaytomicPrivateLeaderboard> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestPrivateLeaderBoardLoadFinished (playtomicResponse.GetObject ()); } else { // we call a function for failed cases // RequestPrivateLeaderBoardLoadFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // load a private leaderboard // leaderboards.LoadPrivateLeaderboard (mBitly);
A complete example of loading a private leaderboard
private void PrivateLeaderboardLoad () { if (mBitly.Length == 0) { L.Log ("You need to save a private leaderboar before loaded it.", this); } else { L.Log ("\nPrivate Leaderboard Load", this); // create a new PlaytomicLeaderboards object // PlaytomicLeaderboards leaderboards = new PlaytomicLeaderboards (); // we need to set a delegate // leaderboards.OnRequestPrivateLeaderboardFinished = delegate (Object sender, PlaytomicResponse<PlaytomicPrivateLeaderboard> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestPrivateLeaderBoardLoadFinished (playtomicResponse.GetObject ()); } else { // we call a function for failed cases // RequestPrivateLeaderBoardLoadFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // load a private leaderboard // leaderboards.LoadPrivateLeaderboard (mBitly); } } private void RequestPrivateLeaderBoardLoadFinished (PlaytomicPrivateLeaderboard leaderboard) { L.Log ("Private Leaderboard {", this); L.Log ("name = " + leaderboard.Name, this); L.Log ("tableId = " + leaderboard.TableId, this); L.Log ("bitly = " + leaderboard.Bitly, this); L.Log ("permalink = " + leaderboard.Permalink, this); L.Log ("highest = " + (leaderboard.Highest ? "yes" : "no"), this); L.Log ("realName = " + leaderboard.RealName, this); L.Log ("}", this); } private void RequestPrivateLeaderBoardLoadFailed (int errorCode, String message) { L.Log ("Leaderboard load failed because of errorcode #" + errorCode + " - Message:" + message, this); }
GameVars let you change the value of key variables in your game any time you want. They must be configured on the edit GameVars page in advance.
You store a bunch of data in Playtomic, have it in your game as a backup for when there's no client connectivity, and then whenever possible, the player can use the most recent values.
All methods are asynchronous. To get a response from this methods the caller must implement the interface PlaytomicRequestListener.
It is called via:
// create a new PlaytomicGameVars object // PlaytomicGameVars vars = new PlaytomicGameVars (); // we need to set a delegate // vars.OnRequestFinished = delegate (Object sender, PlaytomicResponse<String> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestVarsFinished (playtomicResponse.Map); } else { // we call a function for failed cases // RequestVarsFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // load game variables // vars.Load ();
A complete example:
private void LoadGameVars () { L.Log ("\nLoad Game Vars", this); // create a new PlaytomicGameVars object // PlaytomicGameVars vars = new PlaytomicGameVars (); // we need to set a delegate // vars.OnRequestFinished = delegate (Object sender, PlaytomicResponse<String> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestVarsFinished (playtomicResponse.Map); } else { // we call a function for failed cases // RequestVarsFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // load game variables // vars.Load (); } private void RequestVarsFinished (Dictionary<String, String> data) { L.Log ("Vars {", this); foreach (KeyValuePair<String, String> entry in data) { L.Log ("Var: Name=\"" + entry.Key + "\" Value=\"" + entry.Value + "\"", this); } L.Log ("}", this); } private void RequestVarsFailed (int errorCode, String message) { L.Log ("GameVars failed to load because of errorcode #" + errorCode + " - Message:" + message, this); }
The GeoIP service identifies which country the player is from, returning their country code and name.
All methods are asynchronous. To get a response from this methods the caller must implement the interface PlaytomicRequestListener.
It is called via:
// create a new PlaytomicGeoIP object // PlaytomicGeoIP geoIP = new PlaytomicGeoIP (); // create a new PlaytomicGeoIP object // geoIP.OnRequestFinished = delegate (Object sender, PlaytomicResponse<String> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestGeoIPFinished (playtomicResponse.Map); } else { // we call a function for failed cases // RequestGeoIPFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // load Geo IP data // geoIP.Load ();
A complete example:
private void GeoIP () { L.Log ("\nGeoIP", this); // create a new PlaytomicGeoIP object // PlaytomicGeoIP geoIP = new PlaytomicGeoIP (); // create a new PlaytomicGeoIP object // geoIP.OnRequestFinished = delegate (Object sender, PlaytomicResponse<String> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestGeoIPFinished (playtomicResponse.Map); } else { // we call a function for failed cases // RequestGeoIPFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; // load Geo IP data // geoIP.Load (); } private void RequestGeoIPFinished (Dictionary<String, String> data) { L.Log ("GeoIP {", this); foreach (KeyValuePair<String, String> entry in data) { L.Log ("GeoIP: Name=\"" + entry.Key + "\" Value=\"" + entry.Value + "\"", this); } L.Log ("}", this); } private void RequestGeoIPFailed (int errorCode, String message) { L.Log ("GeoIP failed to load because of errorcode #" + errorCode + " - Message:" + message, this); }
Note: You must enable this functionality in each game's settings. By default it is disabled becaue it can expose your game data.
The Data class in the API allows you to retrieve any of your game data to display in your game.
Each function for retrieving data takes an optional parameters object for day, month and year, with default values of 0.
When the request succeeds the returned data is available via:
dat[key];
All methods are asynchronous. To get a response from this methods the caller must implement the interface PlaytomicRequestListener.
The Views, Plays and PlayTime functions returns this data to you for processing:
A complete example:
private void LoadPlays () { L.Log ("\nLoad Plays", this); // create a new PlaytomicData object // PlaytomicData plays = new PlaytomicData (); // we need to set a delegate // plays.OnRequestFinished = delegate (Object sender, PlaytomicResponse<String> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestPlaysFinished (playtomicResponse.Map); } else { RequestPlaysFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; plays.Plays (); } private void RequestPlaysFinished (Dictionary<String, String> data) { L.Log ("Plays {", this); foreach (KeyValuePair<String, String> entry in data) { L.Log ("Plays: Name=\"" + entry.Key + "\" Value=\"" + entry.Value + "\"", this); } L.Log ("}", this); } private void RequestPlaysFailed (int errorCode, String message) { L.Log ("Plays failed to load because of errorcode #" + errorCode + " - Message:" + message, this); } private void LoadPlaytime () { L.Log ("\nLoad Playtime", this); // create a new PlaytomicData object // PlaytomicData playTime = new PlaytomicData (); // we need to set a delegate // playTime.OnRequestFinished = delegate (Object sender, PlaytomicResponse<String> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestPlaytimeFinished (playtomicResponse.Map); } else { RequestPlaytimeFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; playTime.Playtime (); } private void RequestPlaytimeFinished (Dictionary<String, String> data) { L.Log ("Playtime {", this); foreach (KeyValuePair<String, String> entry in data) { L.Log ("Playtime: Name=\"" + entry.Key + "\" Value=\"" + entry.Value + "\"", this); } L.Log ("}", this); } private void RequestPlaytimeFailed (int errorCode, String message) { L.Log ("Playtime failed to load because of errorcode #" + errorCode + " - Message:" + message, this); } private void LoadViews () { L.Log ("\nLoad Views", this); // create a new PlaytomicData object // PlaytomicData views = new PlaytomicData (); // we need to set a delegate // views.OnRequestFinished = delegate (Object sender, PlaytomicResponse<String> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestViewsFinished (playtomicResponse.Map); } else { RequestViewsFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; views.Views (); } private void RequestViewsFinished (Dictionary<String, String> data) { L.Log ("Views {", this); foreach (KeyValuePair<String, String> entry in data) { L.Log ("View: Name=\"" + entry.Key + "\" Value=\"" + entry.Value + "\"", this); } L.Log ("}", this); } private void RequestViewsFailed (int errorCode, String message) { L.Log ("Views failed to load because of errorcode #" + errorCode + " - Message:" + message, this); }
Available keys are:
The CustomMetric function returns data about a custom metric to your function, which receives the same parameters as views/plays/play time above.
A complete example:
private void LoadCustomData () { L.Log ("\nLoad Cutom Data", this); // create a new PlaytomicData object // PlaytomicData customData = new PlaytomicData (); // we need to set a delegate // customData.OnRequestFinished = delegate (Object sender, PlaytomicResponse<String> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestCustomDataFinished (playtomicResponse.Map); } else { // we call a function for failed cases // RequestCustomDataFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; customData.CustomMetric ("hi"); } private void RequestCustomDataFinished (Dictionary<String, String> data) { L.Log ("Custom data {", this); foreach (KeyValuePair<String, String> entry in data) { L.Log ("Custom data: Name=\"" + entry.Key + "\" Value=\"" + entry.Value + "\"", this); } L.Log ("}", this); } private void RequestCustomDataFailed (int errorCode, String message) { L.Log ("Custom data failed to load because of errorcode #" + errorCode + " - Message:" + message, this); }
Available keys are:
Retrieving level metrics is the same as retrieving custom metrics with an additional property for the level name or number.
A complete example:
private void LoadCounters () { L.Log ("\nLoad Counters", this); // create a new PlaytomicData object // PlaytomicData counters = new PlaytomicData (); // we need to set a delegate // counters.OnRequestFinished = delegate (Object sender, PlaytomicResponse<String> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestCountersFinished (playtomicResponse.Map); } else { // we call a function for failed cases // RequestCountersFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; counters.LevelCounterMetric ("hi", "level 1"); L.Log ("\nLoad Average", this); // create a new PlaytomicData object // PlaytomicData average = new PlaytomicData (); // we need to set a delegate // average.OnRequestFinished = delegate (Object sender, PlaytomicResponse<String> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestAverageFinished (playtomicResponse.Map); } else { // we call a function for failed cases // RequestAverageFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; average.LevelCounterMetric ("hi", "level 1", 1, 2010); L.Log ("\nLoad Range", this); // create a new PlaytomicData object // PlaytomicData range = new PlaytomicData (); // we need to set a delegate // range.OnRequestFinished = delegate (Object sender, PlaytomicResponse<String> playtomicResponse) { if (playtomicResponse.Success) { // we call a function for successed cases // RequestRangeFinished (playtomicResponse.Map); } else { // we call a function for failed cases // RequestRangeFailed (playtomicResponse.ErrorCode, playtomicResponse.ErrorMessage); } }; range.LevelCounterMetric ("hi", "level 1", 1, 1, 2010); } private void RequestCountersFinished (Dictionary<String, String> data) { L.Log ("\nCounters {", this); foreach (KeyValuePair<String, String> entry in data) { L.Log ("Counters: Name=\"" + entry.Key + "\" Value=\"" + entry.Value + "\"", this); } L.Log ("}", this); } private void RequestCountersFailed (int errorCode, String message) { L.Log ("\nCounters data failed to load because of errorcode #" + errorCode + " - Message:" + message, this); } private void RequestAverageFinished (Dictionary<String, String> data) { L.Log ("\nAverage {", this); foreach (KeyValuePair<String, String> entry in data) { L.Log ("Average: Name=\"" + entry.Key + "\" Value=\"" + entry.Value + "\"", this); } L.Log ("}", this); } private void RequestAverageFailed (int errorCode, String message) { L.Log ("\nAverage data failed to load because of errorcode #" + errorCode + " - Message:" + message, this); } private void RequestRangeFinished (Dictionary<String, String> data) { L.Log ("\nRange {", this); foreach (KeyValuePair<String, String> entry in data) { L.Log ("Range: Name=\"" + entry.Key + "\" Value=\"" + entry.Value + "\"", this); } L.Log ("}", this); } private void RequestRangeFailed (int errorCode, String message) { L.Log ("\nRange data failed to load because of errorcode #" + errorCode + " - Message:" + message, this); }
Available keys are:
When a Playtomic service is unreachable or has an error it will return a numeric error code. This table describes those errors:
These errors may be returned from any service.
| Code | Meaning |
|---|---|
| 0 | No error |
| 1 | General error, this typically means the player is unable to connect to the Playtomic servers |
| 2 | Invalid game credentials. Make sure you use your SWFID and GUID from the "API" section in the dashboard. |
| Code | Meaning |
|---|---|
| 100 | GeoIP API has been disabled. This may occur if your game is faulty or overwhelming the Playtomic servers. |
| Code | Meaning |
|---|---|
| 200 | Leaderboard API has been disabled. This may occur if your game is faulty or overwhelming the Playtomic servers. |
| 201 | The source URL or name weren't provided when saving a score. Make sure the player specifies a name and the game is initialized before anything else using the code in the "Set your game up" section. |
| 202 | Invalid auth key. You should not see this normally, players might if they tamper with your game. |
| 203 | No Facebook user id on a score specified as a Facebook submission. |
| 204 | Table name wasn't specified for creating a private leaderboard. |
| 205 | Permalink structure wasn't specified: http://website.com/game/whatever?leaderboard= |
| 206 | Leaderboard id wasn't provided loading a private leaderboard. |
| 207 | Invalid leaderboard id was provided for a private leaderboard. |
| Code | Meaning |
|---|---|
| 300 | GameVars API has been disabled. This may occur if your game is faulty or overwhelming the Playtomic servers. |
| Code | Meaning |
|---|---|
| 400 | Level sharing API has been disabled. This may occur if your game is faulty or overwhelming the Playtomic servers. |
| 401 | Invalid rating value (must be 1 - 10). |
| 402 | Player has already rated that level. |
| 403 | The level name wasn't provided when saving a level. |
| 404 | Invalid image auth. You should not see this normally, players might if they tamper with your game. |
| 405 | Invalid image auth (again). You should not see this normally, players might if they tamper with your game. |
| 406 | The level already exists. This is determined via a hash of the game id, level name, player ip address and name, and source url. |
| Code | Meaning |
|---|---|
| 500 | Data API has been disabled. This may occur if the Data API is not enabled for your game, or your game is faulty or overwhelming the Playtomic servers. |