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 call the initInstance method of Playtomic Class.
void onGameStart() {
// init Playtomic API class
//
// Get your credentials from the Playtomic dashboard (add or select game then go to API page)
Playtomic.initInstance(/*replace with gameId*/,
/*replace with gameGuid*/,
/*replace with apikey*/,
this);
Playtomic.Log().view();
}
Premium users can use SSL for all API communication by calling this method after initializing the API but before logging the view:
Playtomic.setSSL();
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.
Note: We are currently changing the naming to Sessions as it is more appropriate today. Changes will be applied in next API version.
public void onStartGame() {
// init Playtomic API
//
// Get your credentials from the Playtomic dashboard (add or select game then go to API page)
Playtomic.initInstance(/*replace with gameId*/, /*replace with gameGuid*/);
// logging a view event
Playtomic.Log().view();
}
This occurs wherever you feel a player has become engaged in your game. It's subjective, previously we recommended putting it on the play button but that is less suitable in a mobile environment so you should use this at some point early in your game where you feel a player has decided to really play your game rather than open it.
Note: We are currently changing the naming to Engages. Changes will be applied in next API version.This data is logged automatically when you send other events.
private void startedGame() {
Playtomic.Log().play();;
// continue starting game
...
Note: This is inherited from the Flash version which runs on a single thread, and is unlikely to be necessary in Java games.
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.
void onPause() {
Playtomic.Log().freeze();
super.onPause();
}
void onResume() {
Playtomic.Log().unfreeze();
super.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 setOfflineQueueMaxSize.
public static void setOfflineQueueMaxSize(int kbSize)
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, name and group 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).
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 | getPlayerName | The name of the player (or "anonymous", "guest", etc), or the name provided by any 3rd party API. |
| playerId | String | getPlayerId | If you're working under a 3rd party API you can include the player's user id |
| playerSource | String | getPlayerSource | If you're working under a 3rd party API you can specify which, eg "gamersafe" or "mochicoins" |
| name | String | getName | The name of the level |
| data | String | getData | The data for the level. You can Base 64 encode a ByteArray to a string if necessary. |
| votes | int | getVotes | The number of votes the level has |
| score | int | getScore | The sum of all votes the level has |
| plays | int | getPlays | The number of plays the level has |
| rating | double | getRating | The rating the level has (score / votes) |
| date | Date | getDate | The date of the level, determined automatically by Playtomic |
| relativeDate | String | getRelativeDate | The relative date of the level eg "7 minutes ago", determined automatically by Playtomic |
| customData | LinkedHashMap<String, String> | getCustomData | Any additional data you want to (or have) attached to a level. |
| String | getThumbnailUrl | Returns the URL of a thumbnail. | |
| Object | getThumbnail | 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);
}
};
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.nextInt();
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");
PlaytomicPlayerLevels playerLevels = new PlaytomicPlayerLevels();
// we need to set a listener
playerLevels.setRequestListener(new PlaytomicRequestListener<PlaytomicLevel>() {
(public void onRequestFinished(PlaytomicResponse<PlaytomicLevel> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestPlayerLevelsSaveFinished(playtomicResponse.getData());
}
else {
// we call a function for failed cases
requestPlayerLevelsSaveFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
playerLevels.save(level);
}
private void requestPlayerLevelsSaveFinished(ArrayList<PlaytomicLevel> data) {
L.log("PlayerLevels Save", this);
Iterator<PlaytomicLevel> itr = data.iterator();
while (itr.hasNext()) {
PlaytomicLevel level = itr.next();
mLevelId = level.getLevelId();
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.
int levelId = /* a level id */;
// create a new PlaytomicPlayerLevels object
PlaytomicPlayerLevels playerLevels = new PlaytomicPlayerLevels();
// we need to set a listener
playerLevels.setRequestListener(new PlaytomicRequestListener<PlaytomicLevel>() {
(public void onRequestFinished(PlaytomicResponse<PlaytomicLevel> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestPlayerLevelsRateFinished();
}
else {
// we call a function for failed cases
requestPlayerLevelsRateFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
// rate a level
playerLevels.rate(levelId, 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() {
PlaytomicPlayerLevels playerLevels = new PlaytomicPlayerLevels();
Playtomic.Log().forceSend();
// we need to set a listener
playerLevels.setRequestListener(new PlaytomicRequestListener<PlaytomicLevel>() {
(public void onRequestFinished(PlaytomicResponse<PlaytomicLevel> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestPlayerLevelsRateFinished();
}
else {
// we call a function for failed cases
requestPlayerLevelsRateFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
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,
LinkedHashMap<String, String> customFilter)
public void list(
String mode,
int page,
int perPage,
Boolean includeData,
Boolean includeThumbs,
LinkedHashMap<String, String> customFilter,
Date dateMin,
Date 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 | LinkedHashMap<String, String> | Filter levels based on custom data you stored with them (eg theme or anything else). |
| andDateMin | Date | The minimum creation date, eg if you wanted popular levels made this week. |
| andDateMax | Date | 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);
PlaytomicPlayerLevels playerLevels = new PlaytomicPlayerLevels();
// we need to set a listener
playerLevels.setRequestListener(new PlaytomicRequestListener<PlaytomicLevel>() {
(public void onRequestFinished(PlaytomicResponse<PlaytomicLevel> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestPlayerLevelsListFinished(playtomicResponse.getData());
}
else {
// we call a function for failed cases
requestPlayerLevelsListFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
playerLevels.list("popular", 1, 10, false, false, null);
}
private void requestPlayerLevelsListFinished(ArrayList<PlaytomicLevel> data) {
L.log("PlayerLevels {", this);
Iterator<PlaytomicLevel> itr = data.iterator();
while (itr.hasNext()) {
PlaytomicLevel level = itr.next();
L.log("----------------------------------\nLevel:\nName=\"" + level.getName() + "\"", this);
L.log("Level Id=\"" + level.getLevelId() + "\"", this);
L.log("Player Name=\"" + level.getPlayerName() + "\"", this);
L.log("Player Source=\"" + level.getPlayerSource() + "\"", this);
L.log("Date=\"" + level.getDate() + "\"", this);
L.log("Relative Date=\"" + level.getRelativeDate() + "\"", this);
L.log("Data=\"" + level.getData() + "\"", this);
L.log("Votes=\"" + level.getVotes() + "\"", this);
L.log("Plays=\"" + level.getPlays() + "\"", this);
L.log("Rating=\"" + level.getRating() + "\"", this);
L.log("Score=\"" + level.getScore() + "\"", this);
L.log("Custom Data {", this);
for (Map.Entry<String, String> entry : level.getCustomData().entrySet()) {
L.log("Var: Name=\"" + entry.getKey() + "\" Value=\"" + entry.getValue() + "\"", this);
}
L.log("}", this);
}
L.log("}", this);
}
private void requestPlayerLevelsListFailed(int errorCode, String message) {
L.log("PlayerLevels List failed to list because of errorcode #" + errorCode
+ " - Message:" + message, 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.getLevelId() |
An example loading a single level
private void levelLoad() {
L.log("\nLevel Load", this);
if(mLevelId.length() == 0) {
L.log("Before load a level you must save one. Use the 'Level Save' button.", this);
}
else {
PlaytomicPlayerLevels playerLevels = new PlaytomicPlayerLevels();
// we need to set a listener
playerLevels.setRequestListener(new PlaytomicRequestListener<PlaytomicLevel>() {
(public void onRequestFinished(PlaytomicResponse<PlaytomicLevel> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestPlayerLevelsLoadFinished(playtomicResponse.getData());
}
else {
// we call a function for failed cases
requestPlayerLevelsLoadFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
playerLevels.load(mLevelId);
}
}
private void requestPlayerLevelsLoadFinished(ArrayList<PlaytomicLevel> data) {
L.log("PlayerLevels {", this);
while (itr.hasNext()) {
PlaytomicLevel level = itr.next();
L.log("----------------------------------\nLevel:\nName=\"" + level.getName() + "\"", this);
L.log("Level Id=\"" + level.getLevelId() + "\"", this);
L.log("Player Name=\"" + level.getPlayerName() + "\"", this);
L.log("Player Source=\"" + level.getPlayerSource() + "\"", this);
L.log("Date=\"" + level.getDate() + "\"", this);
L.log("Relative Date=\"" + level.getRelativeDate() + "\"", this);
L.log("Data=\"" + level.getData() + "\"", this);
L.log("Votes=\"" + level.getVotes() + "\"", this);
L.log("Plays=\"" + level.getPlays() + "\"", this);
L.log("Rating=\"" + level.getRating() + "\"", this);
L.log("Score=\"" + level.getScore() + "\"", this);
L.log("Custom Data {", this);
for (Map.Entry<String, String> entry : level.getCustomData().entrySet()) {
L.log("Var: Name=\"" + entry.getKey() + "\" Value=\"" + entry.getValue() + "\"", this);
}
L.log("}", this);
}
L.log("}", this);
}
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 | getName | The player name. This can be by the player or provided by any 3rd party |
| points | int | getPoints | The player's score |
| rank | int | getRank | The player's rank based on the listing criteria you use. |
| date | Date | getDate | The date of the score, determined automatically by Playtomic |
| relativeDate | String | getRelativeDate | The relative date of the score eg "7 minutes ago", determined automatically by Playtomic |
| customData | LinkedHashMap<String, String> | getCustomData | 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 listener
leaderboards.setRequestListener(new PlaytomicRequestListener<PlaytomicScore>() {
(public void onRequestFinished(PlaytomicResponse<PlaytomicScore> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestLeaderBoardSaveFinished();
}
else {
// we call a function for failed cases
requestLeaderBoardSaveFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
// create a new score
PlaytomicScore score = new PlaytomicScore(/* Constructor parameters */ );
// 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);
PlaytomicLeaderboards leaderboards = new PlaytomicLeaderboards();
// we need to set a listener
leaderboards.setRequestListener(new PlaytomicRequestListener<PlaytomicScore>() {
(public void onRequestFinished(PlaytomicResponse<PlaytomicScore> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestLeaderBoardSaveFinished();
}
else {
// we call a function for failed cases
requestLeaderBoardSaveFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
// create a new score
PlaytomicScore score = new PlaytomicScore("Ben", 2000000);
// add some custom data to the score
LinkedHashMap<String, String> customData = score.getCustomData();
customData.put("cd1", "value1");
customData.put("cd2", "value2");
customData.put("cd3", "value3");
// save the 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 listener
leaderboards.setRequestListener(new PlaytomicRequestListener<PlaytomicScore>() {
(public void onRequestFinished(PlaytomicResponse<PlaytomicScore> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestLeaderBoardListFinished(playtomicResponse.getData());
}
else {
// we call a function for failed cases
requestLeaderBoardListFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
// 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);
PlaytomicLeaderboards leaderboards = new PlaytomicLeaderboards();
// we need to set a listener
leaderboards.setRequestListener(new PlaytomicRequestListener<PlaytomicScore>() {
(public void onRequestFinished(PlaytomicResponse<PlaytomicScore> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestLeaderBoardListFinished(playtomicResponse.getData());
}
else {
// we call a function for failed cases
requestLeaderBoardListFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
leaderboards.list("High scores", true, "alltime", 1, 20, null);
}
private void requestLeaderBoardListFinished(ArrayList<PlaytomicScore> data) {
L.log("Leaderboard {", this);
Iterator<PlaytomicScore> itr = data.iterator();
while (itr.hasNext()) {
PlaytomicScore score = itr.next();
L.log("----------------------------------\nScore:\nName=\"" + score.getName() + "\"", this);
L.log("Points=\"" + score.getPoints() + "\"", this);
L.log("Date=\"" + score.getDate() + "\"", this);
L.log("Relative Date=\"" + score.getRelativeDate() + "\"", this);
L.log("Rank=\"" + score.getRank() + "\"", this);
L.log("Custom Data {", this);
for (Map.Entry<String, String> entry : score.getCustomData().entrySet()) {
L.log("Var: Name=\"" + entry.getKey() + "\" Value=\"" + entry.getValue() + "\"", 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 listener
leaderboards.setRequestListener(new PlaytomicRequestListener<PlaytomicScore>() {
(public void onRequestFinished(PlaytomicResponse<PlaytomicScore> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestLeaderBoardListFinished(playtomicResponse.getData());
}
else {
// we call a function for failed cases
requestLeaderBoardListFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
// list a score
leaderboards.saveAndList("High scores", true, "alltime", 1, 20, 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 listener
leaderboards.setRequestListenerPrivateLeaderboard(new PlaytomicRequestListener<PlaytomicPrivateLeaderboard>() {
public void onRequestFinished(PlaytomicResponse<PlaytomicPrivateLeaderboard> playtomicResponse) {
if (playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestPrivateLeaderBoardSaveFinished(playtomicResponse.getObject());
}
else {
// we call a function for failed cases
requestPrivateLeaderBoardSaveFailed(playtomicResponse.getErrorCode(), playtomicResponse.getErrorMessage());
}
}
});
// create a private leaderboard
leaderboards.createPrivateLeaderboard("Java 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);
PlaytomicLeaderboards leaderboards = new PlaytomicLeaderboards();
// we need to set a listener
leaderboards.setRequestListenerPrivateLeaderboard(new PlaytomicRequestListener<PlaytomicPrivateLeaderboard>() {
public void onRequestFinished(PlaytomicResponse<PlaytomicPrivateLeaderboard> playtomicResponse) {
if (playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestPrivateLeaderBoardSaveFinished(playtomicResponse.getObject());
}
else {
// we call a function for failed cases
requestPrivateLeaderBoardSaveFailed(playtomicResponse.getErrorCode(), playtomicResponse.getErrorMessage());
}
}
});
leaderboards.createPrivateLeaderboard("Java Test", true);
}
private void requestPrivateLeaderBoardSaveFinished(PlaytomicPrivateLeaderboard leaderboard) {
mBitly = leaderboard.getBitly();
L.log("Private Leaderboard {", this);
L.log("name = " + leaderboard.getName(), this);
L.log("tableId = " + leaderboard.getTableId(), this);
L.log("bitly = " + leaderboard.getBitly(), this);
L.log("permalink = " + leaderboard.getPermalink(), this);
L.log("highest = " + (leaderboard.getHighest() ? "yes" : "no"), this);
L.log("realName = " + leaderboard.getRealName(), 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();
leaderboards.setRequestListenerPrivateLeaderboard(new PlaytomicRequestListener<PlaytomicPrivateLeaderboard>() {
public void onRequestFinished(PlaytomicResponse<PlaytomicPrivateLeaderboard> playtomicResponse) {
if (playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestPrivateLeaderBoardLoadFinished(playtomicResponse.getObject());
}
else {
// we call a function for failed cases
requestPrivateLeaderBoardLoadFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
// 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();
leaderboards.setRequestListenerPrivateLeaderboard(new PlaytomicRequestListener<PlaytomicPrivateLeaderboard>() {
public void onRequestFinished(PlaytomicResponse<PlaytomicPrivateLeaderboard> playtomicResponse) {
if (playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestPrivateLeaderBoardLoadFinished(playtomicResponse.getObject());
}
else {
// we call a function for failed cases
requestPrivateLeaderBoardLoadFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
leaderboards.loadPrivateLeaderboard(mBitly);
}
}
private void requestPrivateLeaderBoardLoadFinished(PlaytomicPrivateLeaderboard leaderboard) {
L.log("Private Leaderboard {", this);
L.log("name = " + leaderboard.getName(), this);
L.log("tableId = " + leaderboard.getTableId(), this);
L.log("bitly = " + leaderboard.getBitly(), this);
L.log("permalink = " + leaderboard.getPermalink(), this);
L.log("highest = " + (leaderboard.getHighest() ? "yes" : "no"), this);
L.log("realName = " + leaderboard.getRealName(), 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.
You can load variables individually, for instance if you are caching the GameVars you can check a 'version' GameVar to decide whether to reload the full collection.
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 listener
vars.setRequestListener(new PlaytomicRequestListener<String>() {
(public void onRequestFinished(PlaytomicResponse<String> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestVarsFinished(playtomicResponse.getMap());
}
else {
// we call a function for failed cases
requestVarsFailed(playtomicResponse.getErrorCode(), playtomicResponse.getErrorMessage());
}
}
});
// all variables
vars.load();
// a single variable
vars.loadSingle("Var1");
A complete example:
private void loadGameVars() {
L.log("\nLoad Game Vars", this);
PlaytomicGameVars vars = new PlaytomicGameVars();
// we need to set a listener
vars.setRequestListener(new PlaytomicRequestListener<String>() {
(public void onRequestFinished(PlaytomicResponse<String> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestVarsFinished(playtomicResponse.getMap());
}
else {
// we call a function for failed cases
requestVarsFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
// load game variables
// a single variable
vars.loadSingle("Var1");
// all variables
vars.load();
}
private void requestVarsFinished(LinkedHashMap<String, String> data) {
L.log("Vars {", this);
for (Map.Entry<String, String> entry : data.entrySet()) {
L.log("Var: Name=\"" + entry.getKey() + "\" Value=\"" + entry.getValue() + "\"", 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();
// we need to set a listener
geoIP.setRequestListener(new PlaytomicRequestListener<String>() {
(public void onRequestFinished(PlaytomicResponse<String> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestGeoIPFinished(playtomicResponse.getMap());
}
else {
// we call a function for failed cases
requestGeoIPFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
// load Geo IP data
geoIP.load();
A complete example:
private void geoip() {
L.log("\nGeoIP", this);
PlaytomicGeoIP geoIP = new PlaytomicGeoIP();
// we need to set a listener
geoIP.setRequestListener(new PlaytomicRequestListener<String>() {
(public void onRequestFinished(PlaytomicResponse<String> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestGeoIPFinished(playtomicResponse.getMap());
}
else {
// we call a function for failed cases
requestGeoIPFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
geoIP.load();
}
private void requestGeoIPFinished(LinkedHashMap<String, String> data) {
L.log("GeoIP {", this);
for (Map.Entry<String, String> entry : data.entrySet()) {
L.log("GeoIP: Name=\"" + entry.getKey() + "\" Value=\"" + entry.getValue() + "\"", 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:
data.get(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 loadViews() {
L.log("\nLoad Views", this);
PlaytomicData views = new PlaytomicData();
// we need to set a listener
views.setRequestListener(new PlaytomicRequestListener<String>() {
(public void onRequestFinished(PlaytomicResponse<String> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestViewsFinished(playtomicResponse.getMap());
}
else {
// we call a function for failed cases
requestViewsFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
views.views();
}
private void requestViewsFinished(LinkedHashMap<String, String> data) {
L.log("Views {", this);
for (Map.Entry<String, String> entry : data.entrySet()) {
L.log("View: Name=\"" + entry.getKey() + "\" Value=\"" + entry.getValue() + "\"", this);
}
L.log("}", this);
}
private void requestViewsFailed(int errorCode, String message) {
L.log("Views failed to load because of errorcode #" + errorCode
+ " - Message:" + message, this);
}
private void loadPlays() {
L.log("\nLoad Plays", this);
PlaytomicData plays = new PlaytomicData();
// we need to set a listener
plays.setRequestListener(new PlaytomicRequestListener<String>() {
(public void onRequestFinished(PlaytomicResponse<String> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestPlaysFinished(playtomicResponse.getMap());
}
else {
// we call a function for failed cases
requestPlaysFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
plays.plays();
}
private void requestPlaysFinished(LinkedHashMap<String, String> data) {
L.log("Plays {", this);
for (Map.Entry<String, String> entry : data.entrySet()) {
L.log("Plays: Name=\"" + entry.getKey() + "\" Value=\"" + entry.getValue() + "\"", 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);
PlaytomicData playTime = new PlaytomicData();
// we need to set a listener
playTime.setRequestListener(new PlaytomicRequestListener<String>() {
(public void onRequestFinished(PlaytomicResponse<String> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestPlaytimeFinished(playtomicResponse.getMap());
}
else {
// we call a function for failed cases
requestPlaytimeFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
playTime.playtime();
}
private void requestPlaytimeFinished(LinkedHashMap<String, String> data) {
L.log("Playtime {", this);
for (Map.Entry<String, String> entry : data.entrySet()) {
L.log("Playtime: Name=\"" + entry.getKey() + "\" Value=\"" + entry.getValue() + "\"", this);
}
L.log("}", this);
}
private void requestPlaytimeFailed(int errorCode, String message) {
L.log("Playtime 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);
PlaytomicData customData = new PlaytomicData();
// we need to set a listener
customData.setRequestListener(new PlaytomicRequestListener<String>() {
(public void onRequestFinished(PlaytomicResponse<String> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestCustomDataFinished(playtomicResponse.getMap());
}
else {
// we call a function for failed cases
requestCustomDataFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
customData.customMetric("hi");
}
private void requestCustomDataFinished(LinkedHashMap<String, String> data) {
L.log("Custom data {", this);
for (Map.Entry<String, String> entry : data.entrySet()) {
L.log("Custom data: Name=\"" + entry.getKey() + "\" Value=\"" + entry.getValue() + "\"", 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);
PlaytomicData counters = new PlaytomicData();
// we need to set a listener
counters.setRequestListener(new PlaytomicRequestListener<String>() {
(public void onRequestFinished(PlaytomicResponse<String> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestCountersFinished(playtomicResponse.getMap());
}
else {
// we call a function for failed cases
requestCountersFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
counters.levelCounterMetric("hi", "level 1");
L.log("\nLoad Average", this);
PlaytomicData average = new PlaytomicData();
// we need to set a listener
average.setRequestListener(new PlaytomicRequestListener<String>() {
(public void onRequestFinished(PlaytomicResponse<String> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestAverageFinished(playtomicResponse.getMap());
}
else {
// we call a function for failed cases
requestAverageFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
average.levelCounterMetric("hi", "level 1", 1, 2010);
L.log("\nLoad Range", this);
PlaytomicData range = new PlaytomicData();
// we need to set a listener
range.setRequestListener(new PlaytomicRequestListener<String>() {
(public void onRequestFinished(PlaytomicResponse<String> playtomicResponse) {
if(playtomicResponse.getSuccess()) {
// we call a function for successed cases
requestRangeFinished(playtomicResponse.getMap());
}
else {
// we call a function for failed cases
requestRangeFailed(playtomicResponse.getErrorCode(),
playtomicResponse.getErrorMessage());
}
}
});
range.levelCounterMetric("hi", "level 1", 1, 1, 2010);
}
private void requestCountersFinished(LinkedHashMap<String, String> data) {
L.log("\nCounters {", this);
for (Map.Entry<String, String> entry : data.entrySet()) {
L.log("Counters: Name=\"" + entry.getKey() + "\" Value=\"" + entry.getValue() + "\"", 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(LinkedHashMap<String, String> data) {
L.log("\nAverage {", this);
for (Map.Entry<String, String> entry : data.entrySet()) {
L.log("Average: Name=\"" + entry.getKey() + "\" Value=\"" + entry.getValue() + "\"", 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(LinkedHashMap<String, String> data) {
L.log("\nRange {", this);
for (Map.Entry<String, String> entry : data.entrySet()) {
L.log("Range: Name=\"" + entry.getKey() + "\" Value=\"" + entry.getValue() + "\"", 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. |
| 3 | Request timed out. |
| 4 | Invalid request. This means the request wasn't formed right, probably because the API key wasn't provided or was incorrect. |
| 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. |
| 208 | Player is banned from your leaderboard. |
| 209 | SaveAndList only. The score was not the player's best score. You can message the player, highlight their best via the SubmittedOrBest boolean property of scores, or override this by setting allowduplicates to true. |
| 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. |
| Code | Meaning |
|---|---|
| 600 | You have not configured your Parse.com database. Sign up at Parse and then enter your API credentials in your Playtomic dashboard. |
| 601 | No response was returned from Parse. If you experience this a lot let us know exactly what you're doing so we can sort out a fix for it. |
| 6021 | Parse's servers had an error. |
| 602101 | Object not found. Make sure you include the classname and objectid and that they are correct. |
| 602102 | Invalid query. If you think you're doing it right let us know what you're doing and we'll look into it. |
| 602103 | Invalid classname. |
| 602104 | Missing objectid. |
| 602105 | Invalid key name. |
| 602106 | Invalid pointer. |
| 602107 | Invalid JSON. |
| 602108 | Command unavailable. |
Friends, Playtomic has come to an end. Part of this service will live on at Playtomic.org as a self-hosted, open source platform I am continuing to develop in my spare time. The rest is unfortunately finished.