How to integrate Facebook Instant Games API in your Phaser game – managing leaderboards
Talking about Facebook, Game development, HTML5, Javascript and Phaser.
Learn cross platform HTML5 game development
Check my Gumroad page for commented source code, games and books.
Give your leaderboard a name – it’s just an internal name so don’t worry – and set “Contextual Leaderboard” to “No” as you want your leaderboard to be global, including all Facebook players.
Then, you will save the score on the leaderboard this way:
FBInstant.getLeaderboardAsync("global_leaderboard").then(leaderboard => {
console.log("retrieved leaderboard: " + leaderboard.getName());
return leaderboard.setScoreAsync(this.score);
}).then(() => console.log("Score saved: " + this.score)).catch(error => console.error(error));
global_leaderboard is the leaderboard internal name and this.score is the score you are going to save.
To retrieve scores, use:
FBInstant.getLeaderboardAsync("global_leaderboard") .then(leaderboard => leaderboard.getEntriesAsync(3, 0)).then(entries => {
console.log("TOP SCORES")
for (var i = 0; i < entries.length; i++) {
console.log("#" + entries[i].getRank() + " " + entries[i].getPlayer().getName() + ": " + entries[i].getScore());
}
}).catch(error => console.error(error));
global_leaderboard is the leaderboard internal name and leaderboard.getEntriesAsync(count, offset) means “retrieve count entries starting from offset“.
count has a default value of 10 and can be used to retrieve up to 100 entries.
The complete source code of the game, with new lines highlighted, now is
var game;
var savedData = {
bestScore: 0
};
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(){
FBInstant.player.getDataAsync(["score"]).then(function(data){
if(typeof data["score"] !== "undefined"){
savedData.bestScore = data["score"];
}
game.add.bitmapText(game.width / 2, 440, "whitefont", savedData.bestScore.toString(), 60).anchor.set(0.5, 1);
});
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);
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(){
FBInstant.getLeaderboardAsync("global_leaderboard") .then(leaderboard => leaderboard.getEntriesAsync(3, 0)).then(entries => {
console.log("TOP SCORES")
for (var i = 0; i < entries.length; i++) {
console.log("#" + entries[i].getRank() + " " + entries[i].getPlayer().getName() + ": " + entries[i].getScore());
}
}).catch(error => console.error(error));
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;
FBInstant.player.setDataAsync({
"score": Math.max(savedData.bestScore, this.score)
});
FBInstant.getLeaderboardAsync("global_leaderboard").then(leaderboard => {
console.log("retrieved leaderboard: " + leaderboard.getName());
return leaderboard.setScoreAsync(this.score);
}).then(() => console.log("Score saved: " + this.score)).catch(error => console.error(error));
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);
}
}
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.