Facebook and Unity Tutorial – Part Two

A note before you start: This is a Unity tutorial about implementing Facebook in Unity projects. It’s a technical how-to guide for Unity developers who want to use Facebook Connect in their web-apps. If that sounds interesting, read on! If it does not, you should check this out. And stay tuned for other blog posts. 😉

In part two of our Facebook and Unity Tutorial we’ll learn the following:

  • Sending and storing highscores.
  • Retrieving highscores.
  • Display scores and facebook profile picture.
If you havent already, you should read part one first.

To make a game

In order to get a highscore we’ll need to make a game. For the demonstration we’ll be creating something very simple, but you should be able to use the lessons learned to implement facebook and highscores in your own games. We’ll be creating a dice rolling game, where the user has to click a button to roll a random number.

Create a new project and add the following script:

[sourcecode language=”csharp”]
<pre>public class DiceGame : MonoBehaviour
{
public static string FacebookId = "1"; //We’ll link up with FacebookManager later.
private const int max = 6; //Max score, the sides on the dice
private string btnText = "Press to roll";
void OnGUI()
{
if (GUI.Button(new Rect(10, 10, 200, 50), btnText))
{
int score = UnityEngine.Random.Range(1, max + 1); //Calculate our score.
btnText = string.Format("You rolled {0}, \nclick to try again.", score);

StartCoroutine(submitHighscore(score, FacebookId));
}

}

IEnumerator submitHighscore(int score, string fbid)
{
yield return null; //We’ll implement this later.
}
}
[/sourcecode]

Nothing fancy there, just a button that when clicked generates a random number and starts our mysterious submitHighscore coroutine. This method should do a webrequest to insert the highscores, so lets create the webservice first!

Creating the webservices

In order to store our scores we’ll need a webservice with a database. Luckily we already have a webserver running locally, we can use that to test. Start by creating a simple database.

We’ll need to store our users facebook id, score and it would be nice to know the creationdate too. Create your database by going to PHPMyadmin, make a new database called `highscores` and run the following SQL to generate the database:

[sourcecode language=”SQL”]

CREATE TABLE `highscores`.`scores` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`fbid` TEXT NOT NULL ,
`score` INT NOT NULL ,
`creation_date` TIMESTAMP NOT NULL
) ENGINE = INNODB;

[/sourcecode]

Now we have our database setup lets create the script that will insert our highscores; create a new file called insert_highscore.php in your WWW directory.  

[sourcecode language=”php”]
<?php

mysql_connect(‘localhost’,’root’,”); //Connect to the databsae
mysql_select_db(‘highscores’);

$score = @$_GET[‘score’];
$fbid = @$_GET[‘fbid’];

if(!$score || !$fbid) //Ensure both parameters are passed
die("No fbid or score");

mysql_query("INSERT INTO scores (fbid, score) VALUES (‘$fbid’, $score)"); //Execute the query
?>
[/sourcecode]

The first 2 lines connect to the database server and select the proper database. Next we validate the input, and stop executing if either score or fbid was not supplied. After we’re sure they exist we insert them in the database using SQL.
Great, visit your page at http://localhost/insert_highscore.php?fbid=4&score=1, and verify that there is a new row in the database by going to PhpMyAdmin and clicking on Browse in your scores table.

Now we can insert, we’ll need a way to retrieve the scores too. Create a new page with the name get_highscores.php. We dont want to get all highscores from a user, just the highest one. This is where GROUP BY comes in handy.

[sourcecode language=”php”]
<?php

mysql_connect(‘localhost’,’root’,”);
mysql_select_db(‘highscores’);

$scoresQuery = mysql_query("SELECT
MAX(score) as max_score,
fbid
FROM
scores
GROUP BY
fbid
ORDER BY
max_score DESC");

while($scoresRow = mysql_fetch_assoc($scoresQuery))
echo $scoresRow[‘fbid’] . ‘,’ . $scoresRow[‘max_score’] . "\n";

?>
[/sourcecode]

It connects to the database again, and executes the query. It then outputs each row as follows:

fbid,score
fbid,score
etc..

Check it out by going to http://localhost/get_highscores.php. If required you can add more highscores by going back to insert_highscore.php. Try using different facebook id’s too, you’ll see more rows being displayed by get_highscores.

Inserting data

Now we have the webservices ready we should be able to call them from our Unity game.

[sourcecode language=”csharp”]

private Dictionary<string, int> scores; //The key is the facebook id, value is his score.

void Start()
{
scores = new Dictionary<string, int>();
StartCoroutine(retrieveHighscores()); //Start out by getting the current scores.
}
IEnumerator submitHighscore(int score, string fbid)
{
WWW webRequest = new WWW("http://localhost/insert_highscore.php?score=" + score + "&fbid=" + fbid);
yield return webRequest;

yield return retrieveHighscores(); //After we submit we’d want an update, perhaps someone else played too!
}
IEnumerator retrieveHighscores()
{
WWW webRequest = new WWW("http://localhost/get_highscores.php");
yield return webRequest;

string[] lines = webRequest.text.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); //Split the response by newlines.

scores = new Dictionary<string, int>(); //Always reset our scores, as we just got new ones.
foreach (string line in lines) //Parse every line
{
string[] parts = line.Split(‘,’);

string id = parts[0];
int score = int.Parse(parts[1]);

scores.Add(id,score);
}
}
[/sourcecode]

Great, we call the webpages using Unity’s built in WWW class with the proper GET parameters. Whenever you post highscores it will automaticly retrieve them too. There is some parsing going on again in retrieveHighscores, namely we split them by each line and then by comma.
Our Dictionary contains the scores, with the facebook id as key and their highest score as value.

Drag the script on a gameobject in your scene and try it out in the Editor. Validate everything is working properly by clicking the button a few times and then check if there are new rows added in the database.

Linking Facebook

Our game now stores and retrieves highscores properly , but lets link it up with Facebook. Lets create a FacebookManager to retrieve the ID:

[sourcecode language=”Csharp”]
public class FacebookManager : MonoBehaviour
{
void Start()
{
Application.ExternalCall("GetCurrentUser");
}
public void GetCurrentUserComplete(string fbid)
{
DiceGame.FacebookId = fbid;
}
}
[/sourcecode]

Stick it on a GameObject named FacebookManager and make a web build. Modify the WebPlayer.html to implement the Facebook SDK:

[sourcecode lang=”javascript”]
<script src="http://connect.facebook.net/en_US/all.js"></script>
<script type="text/javascript" src="http://webplayer.unity3d.com/download_webplayer-3.x/3.0/uo/UnityObject.js"></script>
<div id="fb-root"></div>

<script type=’text/javascript’>

//Fired when the facebook sdk has loaded
window.fbAsyncInit = function()
{
FB.init(
{
appId : ‘171298766297727’,
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
oauth : true, // enable OAuth 2.0
xfbml : false // dont parse XFBML
});

//Get the current login status.
FB.getLoginStatus(function(loginStatusResponse)
{
if(!loginStatusResponse.authResponse) //Not logged in, log him in
FB.login();
});

};

function GetCurrentUser() //When we are logged in this shows our name.
{
FB.api(‘/me’, function(meResponse) //Do a graph request to /me
{
getUnity().SendMessage("FacebookManager", //Game object name, make sure this exists!
"GetCurrentUserComplete", //Method to call
meResponse.id); //Our serialized facebook data
});
}

//Load the Facebook JS SDK
(function(d){
var js, id = ‘facebook-jssdk’; if (d.getElementById(id)) {return;}
js = d.createElement(‘script’); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
d.getElementsByTagName(‘head’)[0].appendChild(js);
}(document));

function getUnity()
{
if (typeof unityObject != "undefined")
{
return unityObject.getObjectById("unityPlayer");
}
return null;
}
if (typeof unityObject != "undefined")
{
unityObject.embedUnity("unityPlayer", "WebPlayer.unity3d", 960, 640);
}
</script>

<div id=’unityPlayer’></div>
[/sourcecode]

Open the page and press the button a few times, then go to your database and you’ll see your Facebook ID inserted correctly!

The next step is to do something with the facebook id’s we store, lets show the user’s profile image. As per the Facebook Graph API you can get a users image with the following url: http://graph.facebook.com/UID/picture/

Change your retrieve highscores to this:

[sourcecode lang=”csharp”]
private Dictionary<string, Texture2D> fbProfileImages = new Dictionary<string, Texture2D>();
IEnumerator retrieveHighscores()
{
WWW webRequest = new WWW("http://localhost/fbblog/p2/get_highscores.php");
yield return webRequest;

string[] lines = webRequest.text.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);

scores = new Dictionary<string, int>(); //Always reset our scores, as we just got new ones.
foreach (string line in lines)
{
string[] parts = line.Split(‘,’);

string id = parts[0];
int score = int.Parse(parts[1]);

if (!fbProfileImages.ContainsKey(id)) //Have we already loaded this user before?
{
//No, better get our image!
WWW imageRequest = new WWW("http://graph.facebook.com/" + id + "/picture");
yield return imageRequest;
fbProfileImages.Add(id, imageRequest.texture);
}

scores.Add(id,score);
}
}
[/sourcecode]

And change your OnGUI to:

[sourcecode lang=”csharp”]
void OnGUI()
{
if (GUI.Button(new Rect(10, 10, 200, 50), btnText))
{
int score = UnityEngine.Random.Range(1, max + 1);
btnText = string.Format("You rolled {0}, \nclick to try again.", score);

StartCoroutine(submitHighscore(score, FacebookId));
}

float h = 10;
foreach (var score in scores)
{
GUI.Label(new Rect(300, h, 200, 50), score.Value.ToString());

if (fbProfileImages != null && fbProfileImages.ContainsKey(score.Key))
GUI.DrawTexture(new Rect(230, h, 50, 50), fbProfileImages[score.Key]);

h += 60;
}
}
[/sourcecode]

The fbProfileImages dictionary keeps track of the profile Textures, they get loaded whenever a new user is found. Build and run the project again, and be amazed how easy it is to retrieve someone’s Facebook profile picture.

result1

A great result, but there’s something fishy. Mark Zuckerberg has rolled 7 with a 6 sided dice! In the next part we’ll find out how he did it, and protect ourself against several common attacks used by malicious users.

Download complete project.

32 Comments

Post A Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.