How to integrate Facebook Instant Games API in your Phaser game – displaying player name and profile picture
Last week I blogged about Facebook Instant Games API and how to integrate the SDK in your Phaser game, simply making a game run in Facebook Messenger.
Obviously this is not enough, as there is a lot more to do, like getting player information and selling to Cambridge Analytica display player name and profile picture in the game.
This is the result – only a picture since I did not publish the game yet:
Here you can see my Facebook first name (Emanuele) and my profile picture.
And this is the full source code of Risky Steps with Facebook-specific code highlighted and explained:
Let’s see the new lines in detail:
Lines 14-17: a global object which will contain Facebook information
Line 20: initializing Facebook SDK library. This should be called before any other SDK functions.
Line 21: reporting the progress of initial resource loading. I am setting it directly to 100 because I will preload assets from Phaser
Line 22: to be executed when the game has finished loading resources and is ready to start
Line 23: saving the first name of Facebook user into
Here you can see my Facebook first name (Emanuele) and my profile picture.
And this is the full source code of Risky Steps with Facebook-specific code highlighted and explained:
var game;
var savedData;
var gameOptions = {
gameHeight: 1334,
backgroundColor: 0x08131a,
visibleTargets: 9,
ballDistance: 120,
rotationSpeed: 4,
angleRange: [25, 155],
localStorageName: "riskystepsgame"
}
var facebookStuff = {
name: "",
picture: ""
}
FBInstant.initializeAsync().then(function(){
FBInstant.setLoadingProgress(100);
FBInstant.startGameAsync().then(function(){
facebookStuff.name = FBInstant.player.getName();
facebookStuff.picture = FBInstant.player.getPhoto();
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
if(windowWidth > windowHeight){
windowWidth = windowHeight / 1.8;
}
var gameWidth = windowWidth * gameOptions.gameHeight / windowHeight;
game = new Phaser.Game(gameWidth, gameOptions.gameHeight, Phaser.CANVAS);
game.state.add("Boot", boot);
game.state.add("Preload", preload);
game.state.add("TitleScreen", titleScreen);
game.state.add("PlayGame", playGame);
game.state.start("Boot");
})
})
var boot = function(){};
boot.prototype = {
preload: function(){
game.load.image("loading", "assets/sprites/loading.png");
},
create: function(){
game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
game.scale.pageAlignHorizontally = true;
game.scale.pageAlignVertically = true;
game.stage.disableVisibilityChange = true;
game.stage.backgroundColor = gameOptions.backgroundColor;
game.state.start("Preload");
}
}
var preload = function(){};
preload.prototype = {
preload: function(){
var loadingBar = this.add.sprite(game.width / 2, game.height / 2, "loading");
loadingBar.anchor.setTo(0.5);
game.load.setPreloadSprite(loadingBar);
game.load.image("title", "assets/sprites/title.png");
game.load.image("playbutton", "assets/sprites/playbutton.png");
game.load.image("ball", "assets/sprites/ball.png");
game.load.image("target", "assets/sprites/target.png");
game.load.image("arm", "assets/sprites/arm.png");
game.load.image("homebutton", "assets/sprites/homebutton.png");
game.load.image("tap", "assets/sprites/tap.png");
game.load.image("fog", "assets/sprites/fog.png");
game.load.image("logo", "assets/sprites/logo.png");
game.load.image("profilepicture", facebookStuff.picture);
game.load.bitmapFont("font", "assets/fonts/font.png", "assets/fonts/font.fnt");
game.load.bitmapFont("whitefont", "assets/fonts/whitefont.png", "assets/fonts/whitefont.fnt");
game.load.audio("failsound", ["assets/sounds/fail.mp3", "assets/sounds/fail.ogg"]);
game.load.audio("hitsound", ["assets/sounds/hit.mp3", "assets/sounds/hit.mp3"]);
game.load.audio("hit2sound", ["assets/sounds/hit2.mp3", "assets/sounds/hit2.ogg"]);
},
create: function(){
game.state.start("TitleScreen");
}
}
var titleScreen = function(){};
titleScreen.prototype = {
create: function(){
savedData = localStorage.getItem(gameOptions.localStorageName) == null ? {score: 0} : JSON.parse(localStorage.getItem(gameOptions.localStorageName));
var title = game.add.image(game.width / 2, 50, "title");
title.anchor.set(0.5, 0);
var playButton = game.add.button(game.width / 2, game.height / 2, "playbutton", this.startGame);
playButton.anchor.set(0.5);
var tween = game.add.tween(playButton.scale).to({
x: 0.8,
y: 0.8
}, 500, Phaser.Easing.Linear.None, true, 0, -1);
tween.yoyo(true);
var logoButton = game.add.button(game.width / 2, game.height - 40, "logo", function(){
}, this);
logoButton.anchor.set(0.5, 1);
game.add.bitmapText(game.width / 2, 320, "whitefont", "WELCOME " + facebookStuff.name.toUpperCase(), 48).anchor.set(0.5, 1);
game.add.bitmapText(game.width / 2, 380, "font", "BEST SCORE", 48).anchor.set(0.5, 1);
game.add.bitmapText(game.width / 2, 440, "whitefont", savedData.score.toString(), 60).anchor.set(0.5, 1);
var profileImage = game.add.image(game.width / 2, playButton.y + 250, "profilepicture");
profileImage.anchor.set(0.5);
profileImage.width = 200;
profileImage.height = 200;
},
startGame: function(){
game.state.start("PlayGame");
}
}
var playGame = function(){};
playGame.prototype = {
create: function(){
this.failSound = game.add.audio("failsound");
this.hitSound = [game.add.audio("hitsound"), game.add.audio("hit2sound")];
this.runUpdate = true;
this.score = 0;
this.destroy = false;
this.rotationSpeed = gameOptions.rotationSpeed;
this.targetArray = [];
this.steps = 0;
this.rotatingDirection = game.rnd.between(0, 1);
this.gameGroup = game.add.group();
this.targetGroup = game.add.group();
this.ballGroup = game.add.group();
this.gameGroup.add(this.targetGroup);
this.gameGroup.add(this.ballGroup);
this.arm = game.add.sprite(game.width / 2, 900, "arm");
this.arm.anchor.set(0, 0.5);
this.arm.angle = 90;
this.ballGroup.add(this.arm);
this.balls = [
game.add.sprite(game.width / 2, 900, "ball"),
game.add.sprite(game.width / 2, 900 + gameOptions.ballDistance, "ball")
]
this.balls[0].anchor.set(0.5);
this.balls[1].anchor.set(0.5);
this.ballGroup.add(this.balls[0]);
this.ballGroup.add(this.balls[1]);
this.rotationAngle = 0;
this.rotatingBall = 1;
var target = game.add.sprite(0, 0, "target");
target.anchor.set(0.5);
target.x = this.balls[0].x;
target.y = this.balls[0].y;
this.targetGroup.add(target);
this.targetArray.push(target);
game.input.onDown.add(this.changeBall, this);
for(var i = 0; i < gameOptions.visibleTargets; i++){
this.addTarget();
}
this.homeButton = game.add.button(game.width / 2, game.height, "homebutton", function(){
game.state.start("TitleScreen");
});
this.homeButton.anchor.set(0.5, 1);
this.tap = game.add.sprite(game.width / 8, this.balls[0].y - 50, "tap");
this.tap.anchor.set(0.5);
var fog = game.add.image(0, 0, "fog");
fog.width = game.width;
this.scoreText = game.add.bitmapText(20, 20, "whitefont", "0", 60);
},
update: function(){
if(this.runUpdate){
var distanceFromTarget = this.balls[this.rotatingBall].position.distance(this.targetArray[1].position);
if(distanceFromTarget > 90 && this.destroy && this.steps > gameOptions.visibleTargets){
var ohnoText = game.add.bitmapText(0, 100, "whitefont", "TOO LATE!!", 48);
ohnoText.anchor.set(0.5);
this.targetArray[0].addChild(ohnoText);
this.gameOver();
}
if(distanceFromTarget < 25 && !this.destroy){
this.destroy = true;
}
if(this.steps == gameOptions.visibleTargets){
if(distanceFromTarget < 20){
this.tap.alpha = 1;
}
else{
this.tap.alpha = 0.2;
}
}
this.rotationAngle = (this.rotationAngle + this.rotationSpeed * (this.rotatingDirection * 2 - 1)) % 360;
this.arm.angle = this.rotationAngle + 90;
this.balls[this.rotatingBall].x = this.balls[1 - this.rotatingBall].x - gameOptions.ballDistance * Math.sin(Phaser.Math.degToRad(this.rotationAngle));
this.balls[this.rotatingBall].y = this.balls[1 - this.rotatingBall].y + gameOptions.ballDistance * Math.cos(Phaser.Math.degToRad(this.rotationAngle));
var distanceX = this.balls[1 - this.rotatingBall].worldPosition.x - game.width / 2;
var distanceY = this.balls[1 - this.rotatingBall].worldPosition.y - 900;
this.gameGroup.x = Phaser.Math.linearInterpolation([this.gameGroup.x, this.gameGroup.x - distanceX], 0.05);
this.gameGroup.y = Phaser.Math.linearInterpolation([this.gameGroup.y, this.gameGroup.y - distanceY], 0.05);
}
},
changeBall:function(e){
if(this.tap != null){
this.tap.destroy();
this.tap = null;
}
var homeBounds = this.homeButton.getBounds();
if(homeBounds.contains(e.position.x, e.position.y)){
this.runUpdate = false;
return;
}
this.hitSound[this.rotatingBall].play();
this.destroy = false;
var distanceFromTarget = this.balls[this.rotatingBall].position.distance(this.targetArray[1].position);
if(distanceFromTarget < 20){
var points = Math.floor((20 - distanceFromTarget) / 2);
this.score += points;
this.scoreText.text = this.score.toString();
this.rotatingDirection = game.rnd.between(0, 1);
var fallingTarget = this.targetArray.shift();
var tween = game.add.tween(fallingTarget).to({
alpha: 0,
width: 0,
height: 0
}, 2500, Phaser.Easing.Cubic.Out, true);
tween.onComplete.add(function(target){
target.destroy();
}, this)
this.arm.position = this.balls[this.rotatingBall].position;
this.rotatingBall = 1 - this.rotatingBall;
this.rotationAngle = this.balls[1 - this.rotatingBall].position.angle(this.balls[this.rotatingBall].position, true) - 90;
this.arm.angle = this.rotationAngle + 90;
this.addTarget();
}
else{
var ohnoText = game.add.bitmapText(0, 100, "whitefont", "MISSED!!", 48);
ohnoText.anchor.set(0.5);
this.targetArray[0].addChild(ohnoText);
this.gameOver();
}
},
addTarget: function(){
this.steps++;
startX = this.targetArray[this.targetArray.length - 1].x;
startY = this.targetArray[this.targetArray.length - 1].y;
var target = game.add.sprite(0, 0, "target");
var randomAngle = game.rnd.between(gameOptions.angleRange[0] + 90, gameOptions.angleRange[1] + 90);
target.anchor.set(0.5);
target.x = startX + gameOptions.ballDistance * Math.sin(Phaser.Math.degToRad(randomAngle));
target.y = startY + gameOptions.ballDistance * Math.cos(Phaser.Math.degToRad(randomAngle));
var stepText = game.add.bitmapText(0, 0, "whitefont", this.steps.toString(), 32);
stepText.anchor.set(0.5);
target.addChild(stepText);
this.targetGroup.add(target);
this.targetArray.push(target);
},
gameOver: function(){
this.failSound.play();
var finalSteps = this.steps - gameOptions.visibleTargets;
this.scoreText.text = this.score.toString() + " * " + finalSteps + " = " + (this.score * finalSteps).toString();
this.score *= finalSteps;
localStorage.setItem(gameOptions.localStorageName, JSON.stringify({
score: Math.max(savedData.score, this.score)
}));
this.runUpdate = false;
game.input.onDown.remove(this.changeBall, this);
this.rotationSpeed = 0;
this.arm.destroy();
var gameOverTween = game.add.tween(this.balls[1 - this.rotatingBall]).to({
alpha: 0
}, 1500, Phaser.Easing.Cubic.Out, true);
gameOverTween.onComplete.add(function(){
game.state.start("PlayGame");
},this);
}
}
facebookStuff variable
Line 24: saving the URL of Facebook profile photo into facebookStuff variable
Line 70: preloading Facebook profile picture, given the URL which now we know
Line 100: adding player first name, now that we know it, as a bitmap text. Remember to include special characters in your bitmap text as some names use them.
Lines 103-106: adding player profile picture to splash screen. Now it’s just a Phaser image
Now the game looks much more social, isn’t it?
There’s still a lot to do since Facebook allows a lot more options, but at the moment that’s all, so download the source code and give me feedback.