Thursday 1 January 2015

We decided to add Facebook scores based Leaderboard in our Unity game Hit Bit Hacker and after a bit of research on how to go about it, we finally decided to go with Prime 31's Social Networking Plugin because of the good experience we've already had using some of their other plugins.

We tried out a tutorial from another site to get this plugin working, but found much of the stuff not
working, perhaps because the plugin has been updated...several coffee breaks, extensive debugging and logging later we were finally able to get it working in our game !

What will this tutorial do ?

1. Initial steps and code to setup facebook for your game.

2. Show you how to submit your high score to facebook.

3. Fetch a leaderboard of scores and pics of all your friends who are also playing this game.

1. Initial Steps

Setup your app on facebook developer page and then add those settings in Unity.
Its pretty much straightforward and Prime 31's page shows how to do it, so we won't go into those details here :- 


Next, add a Gameobject in the Unity scene which will represent your Facebook stuff.
Lets call it "FacebookLeaderboard". This is is the basic code that needs to be in. We will
add the score stuff later to this same class : 

#if UNITY_ANDROID
using FacebookWrapper = FacebookAndroid;
#elif UNITY_IPHONE
using FacebookWrapper = FacebookBinding;
#endif

public class FacebookLeaderboard : MonoBehaviour {
private  string FB_APP_ID = "888888888889XYZ"; // replace with your facebook app id

void Awake() {
FacebookWrapper.init();
}
void OnEnable() {
FacebookManager.sessionOpenedEvent += LoginSuccess;
FacebookManager.loginFailedEvent += loginFailedEvent;

FacebookManager.reauthorizationSucceededEvent += ReauthSuccess;
FacebookManager.reauthorizationFailedEvent += reauthorizationFailedEvent;
}

void OnDisable() {
FacebookManager.sessionOpenedEvent -= LoginSuccess;
FacebookManager.loginFailedEvent -= loginFailedEvent;
FacebookManager.reauthorizationSucceededEvent -= ReauthSuccess;
FacebookManager.reauthorizationFailedEvent -= reauthorizationFailedEvent;
}

We won't be going into the details of login and reauthorization permissions here. 
Once the reauthorization success is done, you can post your score to facebook.
You need to have "publish_actions" permission for this.


2. Submit your High Score to Facebook.

Facebook allows you to store one 32 bit integer value for your app and its not a high or
a low score - its simply a value. You have to check it in Unity side whether this is 
a high score or a low score and then post it.

Lets say you decide to post a high score. The first thing to do is fetch your already existing
score on Facebook, so that you can compare if the score that you've made is higher.

Here is how to fetch your score along with it's completion handler : 


void GetMyScore() {
       string request = "me/scores";
       Facebook.instance.graphRequest( request, HTTPVerb.GET, OnGetScoreComplete );
}


void OnGetScoreComplete( string error, object result ) {
          Debug.Log("OnGetScoreComplete result: " + result);
          Dictionary<string, object> resultData = result as Dictionary<string, object>;
// a user might remove the app from facebook settings
if(resultData == null) {
Debug.Log("No app found");
return;
}
// a user might remove the app from facebook settings
if(resultData.ContainsKey("data") == false) {
        Debug.Log("Dictionary does not have data key");
return;
}
List<object> dataList =  resultData["data"] as List<object>;
if(null == dataList) {
Debug.Log("Facebook null list !");
return;
// post your first score if never done before
 if(0 == dataList.Count) {
      PostMyCurrentGameScore();
       return;
}

Dictionary<string, object> objItem = dataList[0] as Dictionary<string, object>;
Dictionary<string, object> userItem = objItem["user"] as Dictionary<string, object>;
Int64 score =  (Int64) objItem["score"]; // Note! : Prime 31 returns a 64-bit int
 
Debug.Log("My retrieved score from Facebook = " + score); 
// no need to post game score if score on fb is more
if (score >= myCurrentGameScore) {
Debug.Log("Score not posted because already higher on Facebook !");
GetLeaderBoard();
return;
}  else {
PostMyCurrentGameScore();
}
   
}


 void PostMyCurrentGameScore() {

     string request = "me/scores"; 
     var parameters = new Dictionary<string,object>()
     {
{  "score", myCurrentGameScore.ToString() }
     };
    Facebook.instance.graphRequest( request, HTTPVerb.POST, parameters, OnPostScoreComplete );
}

 void OnPostScoreComplete( string error, object result ) {
Prime31.Utils.logObject( result );
GetLeaderBoard();
 
 }
3. Fetch a Leaderboard of scores and pics of friends

public void GetLeaderBoard() {
string request = "/" + FB_APP_ID + "/scores"; // get friend scores
Facebook.instance.graphRequest( request, OnLeaderboardComplete );
}

 int m_friendsLoaded = 0;
int m_friendsCount = 0;
void OnLeaderboardComplete(string error, object result) {

Debug.Log(" >>> result: " + result);
Dictionary<string, object> resultData = result as Dictionary<string, object>;
List<object> dataList =  resultData["data"] as List<object>;
if(null == dataList) {
Debug.Log("Facebook leaderboard null list !");
return;
} else {
Debug.Log("Leaderboard Friend List count = " + dataList.Count);
}
m_friendsCount = dataList.Count;

int index = 0;
m_friendsLoaded = 0;
while(index < m_friendsCount) {

Dictionary<string, object> objItem = dataList[index] as Dictionary<string, object>;
Dictionary<string, object> userItem = objItem["user"] as Dictionary<string, object>;
string userID =  userItem["id"] as string;
string name  =  userItem["name"] as string;
Int64 score =  (Int64) objItem["score"];
StartCoroutine(  LoadFriendInfo(index+1, userID   ,  name,  score)  );
index++;
}
 }

IEnumerator LoadFriendInfo(int position, string userID, string name, int score) {
string picURL = "http://graph.facebook.com/" + userID + "/picture?type=small";
WWW www = new WWW(picURL);
yield return www;
float elapsedTime = 0.0f;
while (!www.isDone) {
elapsedTime += Time.deltaTime;
if (elapsedTime >= 5.0f)  {
Debug.Log("Pic fetch time out for" + name);
break;
}
yield return null;
}

Texture2D texPic = www.texture as Texture2D;  // this is the pic you can easily show in Unity

m_friendsLoaded++;
if(m_friendsCount == m_friendsLoaded) {
// done fetching all pics, so you can trigger something here.
}
}


Thats about it!

Here is how the Leaderboards look in Hit Bit Hacker 




To get a better idea, we highly recommend checking it in action:

[iOS] (Facebook scores will get activated by Jan10, 2015) https://itunes.apple.com/app/id948551828


Happy Facebook scoring to your game !