Implementing leaderboards is an activity which many developers want to understand so that they can include them among their game features. Corona supports various services for managing leaderboards including Google Play Games Services and Apple Game Center.
This tutorial will outline one way of setting up your game to use both
This tutorial does not outline setting up your game(s) in iTunes Connect or Google Play. Please refer to the many online resources for those instructions.
For
Your license key, a very long string found within the developer console.
Your
The string that identifies your leaderboard — this looks something like CgkA8kb12jK0onOQBg.
Keep record of all this information since you’ll need to provide it to your Corona app.
Apple Game Center also requires you to gather some information for your app code. When you create a leaderboard, you’ll be asked to give it a unique name. It’s recommended that you follow the com.yourdomain.yourgame.leaderboardname. Make a note of this since you’ll need to specify it within your Corona app.
For each respective service, you’ll need to include the information gathered above within specific areas of your Corona project.
Details on the necessary Google Play Games Services settings can be found in the documentation, but here’s an overview on the necessary aspects:
Implement Google app licensing as outlined here and sign the .apk with a private key as outlined here.
Ensure that you have enabled both Drive API and
Add an entry into the plugins table of build.settings for the
settings = {
plugins =
{
["plugin.gpgs.v2"] =
{
publisherId = "com.coronalabs",
supportedPlatforms = { android=true }
},
},
}
android table of build.settings as the googlePlayGamesAppId key:settings = {
android =
{
googlePlayGamesAppId = "YOUR_APPLICATION_ID",
},
}
Apple Game Center is a bit easier — basically, just include the plugin within the plugins table of build.settings as follows:
settings =
{
plugins =
{
["CoronaProvider.gameNetwork.apple"] =
{
publisherId = "com.coronalabs"
},
},
}
In the Goodbye Globals! tutorial, we outlined how to use a data module to share information between scenes and modules. This technique will be used again to store the various game networking plugin handles used in this tutorial.
globalData.lua and save it to your project directory. Inside, include the following lines:-- Pseudo-global space
local M = {}
return M
main.lua file, require() the data module and add two variables to its table, globalData.gpgs and globalData.gameCenter, both initially set to nil. These will hold the plugin handles for later use.local globalData = require( "globalData" ) local json = require( "json" ) globalData.gpgs = nil globalData.gameCenter = nil
Note that we also require() the JSON library. This is not essential for all implementations, but we’ll use JSON in this tutorial to output game network response data to the console.
Next, let’s test to see what platform the user is on. If it’s an Android device, we’ll require() require() globalData handles configured above.
local globalData = require( "globalData" )
local json = require( "json" )
globalData.gpgs = nil
globalData.gameCenter = nil
local platform = system.getInfo( "platform" )
local env = system.getInfo( "environment" )
if ( platform == "android" and env ~= "simulator" ) then
globalData.gpgs = require( "plugin.gpgs.v2" )
elseif ( platform == "ios" and env ~= "simulator" ) then
globalData.gameCenter = require( "gameNetwork" )
end
Now we’re ready to initialize and log the user in to the proper game network. For this, we’ll first need to add listener functions to handle game network initialization events. Since Lua is a
This is one major point where .init() call. You just to need to login.
-- Google Play Games Services initialization/login listener
local function gpgsInitListener( event )
if not event.isError then
if ( event.name == "login" ) then -- Successful login event
print( json.prettify(event) )
end
end
end
-- Apple Game Center initialization/login listener
local function gcInitListener( event )
if event.data then -- Successful login event
print( json.prettify(event) )
end
end
You can perform additional tasks upon successful login, for instance requesting player information, but for the purpose of this tutorial, we simply output the values returned by the event.
With the listener functions in place, we can now initialize the game network depending on which platform the user is on:
-- Initialize game network based on platform
if ( globalData.gpgs ) then
-- Initialize Google Play Games Services
globalData.gpgs.login( { userInitiated=true, listener=gpgsInitListener } )
elseif ( globalData.gameCenter ) then
-- Initialize Apple Game Center
globalData.gameCenter.init( "gamecenter", gcInitListener )
end
Now that we have the game network initialized and the user is logged in, we’re ready to transmit scores. Normally you would do this after the game is over, or perhaps after the player accomplishes something noteworthy. If you’re tracking the user’s high score locally, you can choose to only transmit a score that you know to be a high score, or alternatively you can send the score to
For this, similar to the initialization process, we’ll need a listener function for submitted scores:
local function submitScoreListener( event )
-- Google Play Games Services score submission
if ( globalData.gpgs ) then
if not event.isError then
local isBest = nil
if ( event.scores["daily"].isNewBest ) then
isBest = "a daily"
elseif ( event.scores["weekly"].isNewBest ) then
isBest = "a weekly"
elseif ( event.scores["all time"].isNewBest ) then
isBest = "an all time"
end
if isBest then
-- Congratulate player on a high score
local message = "You set " .. isBest .. " high score!"
native.showAlert( "Congratulations", message, { "OK" } )
else
-- Encourage the player to do better
native.showAlert( "Sorry...", "Better luck next time!", { "OK" } )
end
end
-- Apple Game Center score submission
elseif ( globalData.gameCenter ) then
if ( event.type == "setHighScore" ) then
-- Congratulate player on a high score
native.showAlert( "Congratulations", "You set a high score!", { "OK" } )
else
-- Encourage the player to do better
native.showAlert( "Sorry...", "Better luck next time!", { "OK" } )
end
end
end
Note that because each network returns different data, we must test for the proper network and handle returned data independently.
With the listener function in place, we can now submit a score to either of the respective services. For this task, you will need the leaderboard identifiers that you acquired from Google or created for Apple. These must exactly match what the service is expecting.
For convenience later on, let’s wrap this in a function which accepts a single score parameter:
local function submitScore( score )
if ( globalData.gpgs ) then
-- Submit a score to Google Play Games Services
globalData.gpgs.leaderboards.submit(
{
leaderboardId = "CgkA8kb12jK0onOQBg",
score = score,
listener = submitScoreListener
})
elseif ( globalData.gameCenter ) then
-- Submit a score to Apple Game Center
globalData.gameCenter.request( "setHighScore",
{
localPlayerScore = {
category = "com.yourdomain.yourgame.leaderboard",
value = score
},
listener = submitScoreListener
})
end
end
Now, submitting a score is as easy as calling the submitScore() function, for example:
submitScore( 10000 )
Games which include leaderboards must logically provide some way for players to view them. This might be triggered from the listener handler of a button widget or, alternatively, it could be shown after the user achieves submitScoreListener() function we already created.
Whatever the method, showing a leaderboard can be done like this:
if ( globalData.gpgs ) then
-- Show a Google Play Games Services leaderboard
globalData.gpgs.leaderboards.show( "CgkA8kb12jK0onOQBg" )
elseif ( globalData.gameCenter ) then
-- Show an Apple Game Center leaderboard
globalData.gameCenter.show( "leaderboards",
{
leaderboard = {
category = "com.yourdomain.yourgame.leaderboard"
}
})
end
While your own game networking implementation can — and probably should — extend beyond just leaderboards, hopefully this tutorial gives you a solid foundation for building