Working with Instant Games API and PlayCanvas Editor

I’m starting to look into FB integration myself, so am keen to find out more and help out where I can.

I wonder is it possible to upload a version of a launcher to the FB developer area, that would then launch the published game on the PlayCanvas site, and give access to the FBInstant object. In this way, you could still do quick tests and changes in the editor, publish, and then re-launch from FB to see the changes.

Hi! I’m too looking at developing instant games using playcanvas. Is there any resource on how to implement the instant games loader for a playcanvas project?

Thanks!

I see what youre saying, it could just be an iframe that you upload to fb webhost, and this points to your playcanvas launch URL.

ill test and report back

looks like iframe will work with published build but not editor launch URL, can playcanvas team comment on this? is there a way round to using iframe in launch URL for testing purposes, and if not, can the published build be unlisted?

1 Like

Any luck with this? @yaustar Im showing the playcanvas loader but I’d prefer to use FBInstant’s instead, right now Im just skipping it and launching into playcanvas

Sorry, haven’t had the time to even start looking at it yet.

@Yohami_Zerpa @yaustar @yqu
Hey Everyone I hope this can help you all. I figured out how to get the loader to work by manipulating the “loading.js” script after building.

Be sure to include the FB instant SDK before building(web build) and downloading. Instructions by Will can be found under the following topic. (It doesn’t matter if you concatenate the scripts or not)

image

• You are basically to unzip the build, edit it, and then zip it up again for deployment on fb instant.
• After the build is unzipped you need to include an “fbapp-config.json” file in the root directory. Mine looks like this

{instant_games: {

    platform_version: "RICH_GAMEPLAY", 

    orientation: "PORTRAIT", 

    override_web_orientation: "PORTRAIT", 

    navigation_menu_version: "NAV_FLOATING", 

    custom_update_templates: {}, surfaceable_stats: {}, 

    match_player_config: {min_context_size: 3, 

        max_context_size: 33}}}

• To get the loader to read accurately and bypass the PlayCanvas loading screen some code needs to be taken out and functions from the FB Instant API need to be implemented.

loading.js

FBInstant.initializeAsync()

    .then(function(){

        pc.script.createLoadingScreen(function (app) {

            var showSplash = function () {

                // **// 

        

            };

        

            var hideSplash = function () {

                // var splash = document.getElementById('application-splash-wrapper');

                // splash.parentElement.removeChild(splash);

                FBInstant.startGameAsync()

                    .then(function() {

                    // Retrieving context and player information can only be done

                    // once startGameAsync() resolves

                    var contextId = FBInstant.context.getID();

                    var contextType = FBInstant.context.getType();

                    var playerName = FBInstant.player.getName();

                    var playerPic = FBInstant.player.getPhoto();

                    var playerId = FBInstant.player.getID();

                    // Once startGameAsync() resolves it also means the loading view has 

                    // been removed and the user can see the game viewport

                    // game.start();

                    });

            };

        

            var setProgress = function (value) {

                // var bar = document.getElementById('progress-bar');

                // if (bar) {

                    value = Math.min(1, Math.max(0, value));

                    value *= 100;

                    // bar.style.width = value * 100 + '%';

                    FBInstant.setLoadingProgress(value);

                // }

            };

        

            var createCss = function () {

                // **//

            };

                

            createCss();

        

            showSplash();

        

            app.on('preload:end', function () {

                app.off('preload:progress');

            });

            app.on('preload:progress', setProgress);

            app.on('start', hideSplash);

        });

        

    });

• Note that all contents of the loading.js file is wrapped in the FBInstant.initializeAsync() .then() function.
• I commented out the contents of the showSplash() and createCss() functions.
• The hideSplash() function I modified looks like this.

var hideSplash=function() {
                // var splash = document.getElementById('application-splash-wrapper');
                // splash.parentElement.removeChild(splash);
                FBInstant.startGameAsync()
                    .then(function() {
                    // Retrieving context and player information can only be done
                    // once startGameAsync() resolves
                    var contextId = FBInstant.context.getID();
                    var contextType = FBInstant.context.getType();
                    var playerName = FBInstant.player.getName();
                    var playerPic = FBInstant.player.getPhoto();
                    var playerId = FBInstant.player.getID();

                    // Once startGameAsync() resolves it also means the loading view has 
                    // been removed and the user can see the game viewport

                    // game.start();
                    });
            };

• The setProgress() function is the most important. What I did was simply modify the value to work with the instant games function and finally passed that value into the FBInstant.setLoadingProgress() function.

var setProgress = function (value) {
                // var bar = document.getElementById('progress-bar');
                // if (bar) {
                    value = Math.min(1, Math.max(0, value));
                    value *= 100;
                    // bar.style.width = value * 100 + '%';
                    FBInstant.setLoadingProgress(value);
                // }
            };

After making these modifications and then zipping the folder once again, the FBInstant loading screen should work as desired.

3 Likes

Brilliant, I’ll give it a try

Works, here’s my version of the loading.js for future reference

        FBInstant.initializeAsync().then( function()
        {
            pc.script.createLoadingScreen(function (app) 
            {
                app.on('preload:end', function () 
                {
                    app.off('preload:progress');
                });

                app.on('preload:progress', function (value)
                {
                    FBInstant.setLoadingProgress( value*100 )
                });

                app.on('start', function()
                {
                    FBInstant.startGameAsync().then(function(){})
                });
            });
        });
            
1 Like

@Yohami_Zerpa glad to know, and thanks for your improved and concise code!

1 Like

@Grayson_Ewing extra question - how do I hide the Playcanvas canvas while the app is loading? it’s rendering the screen black and covering the FBInstant loader after some point

@Yohami_Zerpa does the problem still occur if you copy and paste my code exactly? I also had some problems when i completely removed certain function like the createCss() or showSplash(). Try experimenting and including/excluding different functions to see i you can get your desired result

Nevermind it works, I had uploaded the wrong code X-)

1 Like

@Grayson_Ewing Thank you for your new contributions, I have tried this for a long time. I added fbapp-config.json and edited loading.js before recompressing as you suggested. However, I still can’t get the game to start. Did I forget something?

    var setProgress = function (value) {
        try {
             FBInstant.setLoadingProgress(value*100);
            if(value*100>=100) {
                    setTimeout(()=>{
                        FBInstant.startGameAsync().then(function() {
                            console.log('started');    
                        },this);
                    },1000);
                }
                } catch(ex) {
                    
                }

        
        let setLoad = new CustomEvent("setLoad", {detail:{loadValue:value}});
        window.dispatchEvent(setLoad);

    };

Heres mine

Dont forget to edit the index html of the published build.

This is obviously not a copy paste situation, think about setting that loading progress bar and other functions and how everything loads.

I had the same issue with the workflow. From the Facebook dev website, I found their github with examples on the usage of the SDK for Instant Games:

In one of the examples, they use a mock SDK script, to simulate the original one.

I simply attached it to the root of my project. The benefit is that now I can make proper SDK calls and I don’t need to upload the project to Facebook for checking if the changes are correct, or using a localhost, as described here - it still requires me to download my project first and place it to the http-server folder, which is cumbersome. The only thing - I comment out the section, where the real SDK is inserted in this tutorial:

(function () {
    var _fb = false;
    var _pc = false;
    var _inst = null;
    var app = null;
    
    app = pc.Application.getApplication();
    app.on("initialize", function () {
        if (_fb) {
            app.fire("fb:init");
        }        
    });

    app.on('preload:end', function() {
        
        FBInstant.initializeAsync().then(function() {
            FBInstant.setLoadingProgress(100);
            FBInstant.startGameAsync().then(onStart);
        });
    });
    
    function onStart() {
        _fb = true;
        if (app) {
            app.fire('fb:init');
        } 
    }
    
    // (function(d, s, id){
    //     var js, fjs = d.getElementsByTagName(s)[0];
    //     if (d.getElementById(id)) {return;}
    //     js = d.createElement(s); js.id = id;
    //     js.src = "//connect.facebook.net/en_US/fbinstant.6.3.js";
    //     fjs.parentNode.insertBefore(js, fjs);
    // }(document, 'script', 'facebook-jssdk'));  
}());

The downside is that the mock SDK will return some random data (which you can actually change yourself to simulate the conditions you need), instead of real data. At least, you can be sure your function calls are correct and you have handlers in place, then you can test in Facebook environment, by disabling the mock SDK and uncommenting the lines responsible for fetching the real SDK.

Edit:
Posted my setup script.

1 Like

Finally the game is ready to go to Facebook. Thk @yqu

1 Like

How are you enabling the real SDK and disabling the mock when you create a build?

Are you manually editing every build code, did you create a build script for it or is there an easier way using PlayFab tools?

I’ve been playing around with the FB Instant Games SDK myself. I’ve considered different ways to set up the SDK from a PlayCanvas app exported from the Editor. Editing __start__.js seemed to work pretty well. I just modified the end:

    var configure = function () {
        app.configure(CONFIG_FILENAME, function (err) {
            if (err) {
                console.error(err);
            }

            configureCss(app._fillMode, app._width, app._height);

            // do the first reflow after a timeout because of
            // iOS showing a squished iframe sometimes
            setTimeout(function () {
                reflow();

                window.addEventListener('resize', reflow, false);
                window.addEventListener('orientationchange', reflow, false);

                app.preload(function (err) {
                    if (err) {
                        console.error(err);
                    }

                    app.loadScene(SCENE_PATH, function (err, scene) {
                        if (err) {
                            console.error(err);
                        }

                        FBInstant.startGameAsync().then(function () {
                            app.start();
                        });
                    });
                });
            });
        });
    };

    FBInstant.initializeAsync().then(function() {

        app.once('preload:end', function () {
            FBInstant.setLoadingProgress(100);
        });

        app.on('preload:progress', function (value) {
            value = Math.min(1, Math.max(0, value));
            FBInstant.setLoadingProgress(value * 100);
        });

        if (PRELOAD_MODULES.length > 0) {
            loadModules(PRELOAD_MODULES, ASSET_PREFIX, configure);
        } else {
            configure();
        }
    });

I also delete the loading screen script from the index.html (since it’s not needed because FBIG shows a native loading screen).

It should be pretty easy to write a little Node.js tool that downloads a build and makes these modifications automatically.

2 Likes

Hi Will, thanks for your response.

Indeed, a couple of days a go I created a Node script that downloads the build through the REST API and then performs the required changes to make the generated project IG compatible.

My steps work like this:

1 - Request build, download and unzip it
2 - Inject a reference to the official FB IG SDK inside the index.html
3 - Replace “__loading__.js” with a version that handles loading through FBInstant (instead of __start__.js)
4 - Add the fbapp-config.json file
5 - On the mock SDK that LeXXiK mentioned, I replace then “FBInstant” with “Mock” to make sure it doesn’t override the official one.

Step 5 is a little tricky since it leaves some unused code in the final build, so what’s why I wanted to know if there’s an easy way to have the mock SDK used on the editor but not exported into the build.

Alright, well the time has passed since then, so did my build setup :slight_smile: Modifying the loading.js or start.js as showed by Will and others is a good way. This is for the downloaded build, though. Mock SDK can help you with editing stuff live, inside the Playcanvas Editor. For example, getting a mock response with list of friends and creating a UI for it, all without downloading, etc.

Once you downloaded the build, though, you may and should use the real SDK.

Nevertheless, in your particular setup, I would recommend creating separate tasks - one for setting up the files for local development (lets call it “local”), and another for the release (“release”). So your “release” task could have all the tasks from “local”, plus extra, like substituting loading scripts, removing unneeded files, minifying, zipping, etc. This goes a bit beyond the purpose of this forum, so I will PM you.