In this post(or maybe one more) we would integrate scoreoid with libgdx for Android environment. Before we start, check out Scoreoid here. Let me quote from their site “Scoreoid is a non-restrictive, reliable and easy to use server platform for game developers designed to handle but not limited to leaderboards, game achievements, player login, in-game features, built in CRM features and game management including advanced functions such as platform content awareness, for multi-platform games.” . In other words its awesome and it is free.
We used Scoreoid for our last two games TapShootZombie and SpeedboatSanta and we were really happy with the result because its easy to integrate, it uses web services (REST) to handle all the features so it is easy to implement in any platform and no need to include any library with the game, because as we mentioned it uses web based services. And when we thought of publishing SpeedboatSanta for Html5 we just had to write code for html5 and now we can compare android and html5 game scores.
Ok lets start. First goto Scoreoid, add a developer account, create a game after which you will get two strings -> API Key and Game ID which would be needed to get game data. In this post we would be just calling a service to get players best scores but it can be expanded for other features very easily. You can create players/scores though Scoreoid Console to test the code.
In this example we would have a sprite in the game which on clicked would open highscores window. Highscore window would be an android activity with a list view to display all the scores. In the end we will provide the eclipse project which you can download and import it in the workspace to play with it.
We would make a interface -> ScoreInterface with a function called OpenHighScores() which would be implemented differently in Android,HTML5 and would show a list with scores. For now we focus on android, in some of the later tutorials we would cover GWT part. Here is how ScoreInterface.java looks.
[sourcecode language=”java”]
public interface ScoreInterface {
public void OpenHighScores();
}
[/sourcecode]
You can check older tutorial (Writing Android Specific Code in Libgdx) to see how to implement platform specific code in Libgdx so i won’t go into details here. The mainActivity in Android would implement ScoreInterface and we would pass this object to our ApplicationListener super class (starting point for a libgdx game). Below is a snippet of what i was talking out.
[sourcecode language=”java”]
public class MainActivity extends AndroidApplication implements ScoreInterface {
Handler handler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration cfg = new AndroidApplicationConfiguration();
cfg.useGL20 = false;
//To queue new threads in Main UI Threads
handler=new Handler();
//Call new ApplicationListener object with this argument as
//MainActivity implements ScoreInterface
initialize(new ScoreoidExample(this), cfg);
}
}
[/sourcecode]
So in the game code if we call this function we would be able to see the scores activity in Android (as we will implement the changes in Android) but no change would happen in the desktop application (because we will leave this function empty).
For ScoreActivity we need to do the following :-
- Custom Layout for ListView item having three textviews (Rank, Player Name & Score) which would be inflated when we add scores.
- Create a data adapter to load in the list view to show the scores
- AsyncTask to read scores over the internet using Scoreoid Api.
- Scoreoid Wrapper to make http calls and receive response from Scoreoid Api.
- A JSON Parser to parse the data in the required object (rank, player and score) and update the list view with them.
List View Item :-
We would make an xml layout with three text views to hold Rank, Player Name and Score. Below is the snippet.
[sourcecode language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="30dp" >
<TextView
android:id="@+id/playerPosition"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:paddingLeft="5dp"
android:textColor="@color/White" />
<TextView
android:id="@+id/playerTitle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toRightOf="@+id/playerPosition"
android:paddingLeft="5dp"
android:textColor="@color/White" />
<TextView
android:id="@+id/playerScore"
android:layout_width="100dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:textColor="@color/White" />
</RelativeLayout>
[/sourcecode]
List Adapter :-
Here is the snippet of the custom data adapter.
[sourcecode language=”java”]
//Score class to hold scores we retrieve from Scoreoid
public class Score {
public String PlayerName;
public String ScoreValue;
public long Position;
public Score(String pn,String sv){
Set(pn,sv);
}
public void Set(String pn,String sv){
PlayerName=pn;
ScoreValue=sv;
}
}
//We will attach this adapter with list view to show the scores in the activity
class ScoreAdapter extends BaseAdapter{
List<Score> scores;
//To inflate the custom list-view-item layout dynamically
LayoutInflater inflater;
public ScoreAdapter(Context ctx,List<Score> scores){
inflater = (LayoutInflater) ctx
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.scores=scores;
}
public int getCount() {
// TODO Auto-generated method stub
if (scores != null)
return scores.size();
return 0;
}
public Object getItem(int position) {
// TODO Auto-generated method stub
if (scores != null && position >= 0 && position < getCount())
return scores.get(position);
return null;
}
public long getItemId(int position) {
// TODO Auto-generated method stub
if (scores != null && position >= 0 && position < getCount())
return position;
return 0;
}
//Here we inflate list item view and update it with score values
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View view = convertView;
Score sc = scores.get(position);
if (view == null) {
view = inflater
.inflate(R.layout.list_score_item, parent, false);
}
TextView pTitle = (TextView) view.findViewById(R.id.playerTitle);
TextView pScore = (TextView) view.findViewById(R.id.playerScore);
TextView pPos=(TextView) view.findViewById(R.id.playerPosition);
if (pTitle != null)
pTitle.setText(sc.PlayerName);
if (pScore != null)
pScore.setText(sc.ScoreValue);
if(pPos!=null)
pPos.setText(""+String.valueOf(sc.Position)+".");
return view;
}
}
[/sourcecode]
In the getview function we inflate the view which we want to show in the row in the list view. Then we update the values with the scores and return the udpated view.
In the activity we would just set an empty data adapter to the list view and when we get the data from scoreoid, we would update the scores array and notify the data adapter. Then the scores would start showing in the view.
AsyncTask to make Http Requests :-
With changes in new Android API (I guess 4.0),we are required to do network intensive tasks in an AsyncTask before it was optional. Anyways it is always good to use AsyncTask when we fetch something from internet. Here is the snippet.
A class to hold constants
[sourcecode language=”java”]
public class ScoreoidConstants {
public static final String SCOREOID_APIKEY="PLACE YOUR API KEY HERE !!!";
public static final String SCOREOID_GAME_ID="PLACE YOUR GAME ID HERE !!!";
public static final String SCOREOID_BUNDLE_API="api";
public static final String SCOREOID_BUNDLE_SCORESTART="scoreStart";
public static final String SCOREOID_BUNDLE_LIMIT="limit";
public static final String SCOREOID_URL="https://www.scoreoid.com/api/";
public static final String SCOREOID_RESPONSETYPE="json";
public static final String SCOREOID_SCORE_ORDERBY="score";
public static final String SCOREOID_SCORE_ORDER="desc";
public static final String GETBESTSCORES="getBestScores";
}
[/sourcecode]
Class extending AsyncTask to make run in background to fetch scoreoid scores.
[sourcecode language=”java”]
public class WebService extends AsyncTask<Bundle, String, String>{
//Player’s Rank
long startPosition;
@Override
protected String doInBackground(Bundle… arg0) {
// TODO Auto-generated method stub
String response="";
if(arg0[0]!=null){
// THIS TO CHECK WHICH API CALL IS MADE. FOR THIS EXAMPLE WE ARE
// CALLING ONLY HIGHSCORES
// String api=arg0[0].getString(ScoreoidConstants.SCOREOID_BUNDLE_API);
long limit=arg0[0].getLong(ScoreoidConstants.SCOREOID_BUNDLE_LIMIT);
long start=arg0[0].getLong(ScoreoidConstants.SCOREOID_BUNDLE_SCORESTART);
//The scores return would be in descending order by score value
response=scoreoidObject.GetBestScores(start, limit);
//As the scores are in descending order we would just calculate rank
//by incrementing the start values by 1 during the loop
startPosition=start+1;
}
return response;
}
@Override
protected void onPostExecute(String response) {
// TODO Auto-generated method stub
if(response!=null && response!=""){
List<Score> tempScores= parser.ParseScores(response);
if(tempScores!=null && tempScores.size()>0){
scores.clear();
for(Score s:tempScores){
s.Position=startPosition;
scores.add(s);
startPosition++;
}
//To notify the list view to show the updated scores
adapter.notifyDataSetChanged();
}else{
Toast.makeText(getApplicationContext(), "No scores Available or Some Error Ocurred",
Toast.LENGTH_SHORT).show();
}
}
super.onPostExecute(response);
}
}
[/sourcecode]
So we call the task with a bundle where we put data like which Scoreoid Api to call, with the different parameters required for the call. For this example we are using only one api , so we just mention the start and limit of number of scores we need from scoreoid.
Then we make the http call to Scoreoid and get the response which is json (you can set that to be xml also). After that we parse the data and update the list which we would do in the next two steps.
Scoreoid Wrapper :-
In this class we would do a http post to retreive the data from scoreoid.
[sourcecode language=”java”]
public class ScoreoidWrapper {
DefaultHttpClient httpClient;
HttpContext localContext;
String webServiceUrl;
Handler handler;
HttpPost httpPost = null;
HttpResponse response = null;
public ScoreoidWrapper(){
HttpParams myParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(myParams, 10000);
HttpConnectionParams.setSoTimeout(myParams, 10000);
httpClient = new DefaultHttpClient(myParams);
localContext = new BasicHttpContext();
//Scoreoid API BASE URL
webServiceUrl = ScoreoidConstants.SCOREOID_URL;
handler=new Handler();
}
String webInvoke(String methodName,List<NameValuePair> params){
httpPost = new HttpPost(webServiceUrl + methodName);
String data = "";
try {
//Passing the parameters
httpPost.setEntity(new UrlEncodedFormEntity(params));
//Getting HttpResponse
response = httpClient.execute(httpPost);
//Reading the content part of the response
InputStream is = response.getEntity().getContent();
BufferedInputStream bis = new BufferedInputStream(is);
ByteArrayBuffer baf = new ByteArrayBuffer(20);
int current = 0;
while ((current = bis.read()) != -1) {
baf.append((byte) current);
}
//Convert the reponse to string to parse it later
String ret = new String(baf.toByteArray());
// Response from the server
data = ret;
} catch (Exception e) {
// Exception handling
}
return data;
}
}
[/sourcecode]
JSON Parser :-
After getting the response (in Json format) we parse the result and fill scores array with player’s first name and score value and return the array list.
[sourcecode language=”java”]
public class JSONParser {
List<Score> scores;
public JSONParser(){
scores=new ArrayList<Score>();
}
public List<Score> ParseScores(String response){
scores.clear();
if(response==null)
return scores;
try {
//For parsing the data just look at the content in the Scoreoid Console
//and then we can understand the structure of the return data
//We receive a json array of player scores
JSONArray json=new JSONArray(response);
for (int i = 0; i < json.length(); i++) {
//To get each player score object from the array
JSONObject jsonObject = json.getJSONObject(i);
//Inside this object we have two objects of Player and Score
//Get Player Object’s json string
String player=jsonObject.getString("Player");
//Create json object from player String
JSONObject playerobj=new JSONObject(player);
//Retrieve the player first name
String playerFName=playerobj.getString("first_name");
if(playerFName.equals(""))
playerFName=playerobj.getString("username");
//Get Score object’s json string
String scoreStr=jsonObject.getString("Score");
//Create json object from score string
JSONObject scoreobj=new JSONObject(scoreStr);
//Retrieve score
String score=scoreobj.getString("score");
//Create a Score object and add it in the arraylist
scores.add(new Score(playerFName, score));
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return scores;
}
}
[/sourcecode]
In PostExecute code of the AsyncTask we get the scores parsed and then loop through them to get the player rank. In the end we update the adapter with the new scores and list view is notified. Here is the snippet of the AsyncTask (same as above in the section where we showed AsyncTask code).
[sourcecode language=”java”]
JSONParser parser
protected void onPostExecute(String response) {
// TODO Auto-generated method stub
if(response!=null && response!=""){
List<Score> tempScores= parser.ParseScores(response);
if(tempScores!=null && tempScores.size()>0){
scores.clear();
for(Score s:tempScores){
s.Position=startPosition;
scores.add(s);
startPosition++;
}
//To notify the list view to show the updated scores
adapter.notifyDataSetChanged();
}else{
Toast.makeText(getApplicationContext(), "No scores Available or Some Error Ocurred",
Toast.LENGTH_SHORT).show();
}
}
super.onPostExecute(response);
}
[/sourcecode]
Source Code:
Finally the source code with all the snippets mentioned above which can be imported in eclipse workspace. Download from Box.net
Note :- Input your Scoreoid API Key and Game ID in ScoreoidConstants.java file for the code to show some data.
When you run the example click on the trophy icon at the centre to see the scores.
If you have any query/suggestion/feeback please put it in the comments section.
Thanks
Hello good sir,
Will there be another tutorial for desktop versions? Would be quite awesome! Will now see if i can get this cutie integrated to my game with this tutorial, thanks so much for writing it!
Hi,
Glad to know this is helpful. Actually we only tried integrating scoreoid in android and gwt(html5). So if you wish we can post a tutorial for integrating it in gwt.
Thanks
Hi Rahul, thanks for answering! Now I can say: yes, very helpful. Got it to work with posting scores as well in just a few hours without any prior knowledge, awesome! I do not know which desktop frontend I will use for my game up to now so any tutorial would be helpful!
Thanks again,
Daranus
Hi Daranus,
We posted a tutorial on integrating Scoreoid in libgdx/desktop. Check it out. Hopefully it helps.
Thanks,
Rahul