Saturday, October 3, 2020

Create a Rock Paper Scissors Game with Firebase Realtime Database and Hosting service

What is Firebase Realtime Databases?

Firebase is Google's mobile platform that helps you quickly develop high-quality apps and grow your business. Firebase Realtime Database is a cloud NoSQL database that is using data synchronization to update all connected client devices in real time. It has very friendly IOS, Android and JavaScript SDK and REST API for client-side developers to use.


RPS-Multiplayer

In this blogger, we build a Rock Paper Scissors game. Our program will pair up two players and tell the player who is available if his/her opponent is offline and someone is waiting at the same time. Players can send message to each other, but all previous messages will be remove if player has new opponent.

Step 1:

In the Firebase console, click Add project, then follow the on-screen instructions to create a Firebase project called "RPS-game".

After you create the project, select your project on the console and "Realtime Database" on the right panel. Click on the "Create Database" and follow the on-screen instructions to create your database. Select "Test mode" for your database.


Step 2:

Create a folder has this structure:

├── README.md
├── assets
│   ├── css
│   │   └── style.css
│   ├── images
│   └── javascript
│       └── game.js
└── index.html

Step 3:

Import Firebase JavaScript SDK with CDN in index.html:

<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
 
<script src="https://www.gstatic.com/firebasejs/7.22.0/firebase-app.js"></script>

Step 4:

Obtain your config info from this your project's console:




If you have difficulty to find the config info, follow Firebase Help page: https://support.google.com/firebase/answer/7015592

Initialize Firebase in assets/javascript/game.js:

 // Set the configuration for your app
 
// TODO: Replace with your project's config object
 
var config = {
    apiKey
: "apiKey",
    authDomain
: "projectId.firebaseapp.com",
    databaseURL
: "https://databaseName.firebaseio.com",
    storageBucket
: "bucket.appspot.com"
 
};
  firebase
.initializeApp(config);

 
// Get a reference to the database service
 
var database = firebase.database();

Step 5:

The main logic of the game is in the assets/javascript/game.js. Let's focus on some of the main functions to achieve functionalities of the game.

 // find player who waits for the longest
player_ref.orderByChild("waitTime").limitToLast(1).once("value",function(snapshot){                       
    // check if anyone is waiting to play game
    checkIfSomeoneWaiting(snapshot.val());

    // save player1's info into database
    savePlayer1Info();

    // check if we have update in enemy property
    checkIfHaveEnemy();
                        
    // check database and render player1's choice and score
    initPlayer1Game();

    // check if player1 makes a choice
    database.ref("players/"+my_key+"/choice").on("value",function(snapshot){
        my_choice = snapshot.val();
        if(my_choice !== "" && enemy_choice !== ""){ // if player2 has made a choice
            checkWhoWin();
        };
    })

    // handle player1 offline event
    handlePlayer1Offline();

     // clear the start input
     $("#player_name").val("");
}) 

checkIfSomeoneWaiting(snapshot.val()) has the player that wait for the longest time as argument. If this player hasn't started playing with anyone, pair this player up with the current player.

 function checkIfSomeoneWaiting(data){
    if(data !== null){ // if there is someone waiting to play game
        var key = Object.keys(data)[0];
        if(data[key].enemy === ""){  // if the returned player isn't playing with someone
            my_enemy_key = key;
            enemy = data[my_enemy_key].name;
            wait_time = Number.MAX_VALUE;

            // set myself as the enemy of the returned player and waitTime to min integer 
            database.ref("players/"+my_enemy_key).update({enemy: my_name, waitTime: wait_time});                                 
        }
    } 
}

savePlayer1Info() save current player's info into the database.

function savePlayer1Info(){
    var player1_info = { 
        name: my_name,
        enemy: enemy,
        waitTime: wait_time,
        choice: "",
        online: true,
        message: ""
    }
    database.ref("players/"+my_key).update(player1_info);
}

checkIfHaveEnemy() fires a listener on current player's "enemy" data field. On this field has update, the realtime database with use the callback function "function(snapshot)" here to perform a serial of actions and fire more listeners to listening on the enemy's input, determine who is the winner, incoming new message, and terminate the game if the enemy is offline.

function checkIfHaveEnemy(){
    database.ref("players/"+my_key+"/enemy").on("value",function(snapshot){
        var data = snapshot.val();
        if(data !== ""){
            player_ref.orderByChild("name").equalTo(data).once("value",function(snap){
                my_enemy_key = Object.keys(snap.val())[0];
                var enemy_data = snap.val()[my_enemy_key];
                
                if(enemy_data !== null && (enemy_data.enemy === "" || enemy_data.enemy === my_name)){
                    wait_time = Number.MAX_VALUE;
                    database.ref("players/"+my_enemy_key).update({enemy: my_name, waitTime: wait_time});

                    // render player2's choice and score
                    enemy = enemy_data.name;
                    $("#player2_name").text(enemy);
                    printChoice("#player2_choice");
                    printScore("#player2_result",my_lose,my_win,my_tie);
                    $("#dialogue").empty();

                    // check if there is a new message from player2
                    checkNewMessage();

                    database.ref("players/"+my_enemy_key+"/choice").on("value",function(snapshot){
                        enemy_choice = snapshot.val();
                        if(enemy_choice !== "" && my_choice !== ""){
                            checkWhoWin();
                        }
                    })

                    // handle enemy offline event
                    enemyOfflineHandle();
                }else{
                    $("#player2_choice").append("<p>Sorry,"+data+" is not available!")
                }
            })
        }       
    })
}

initPlayer1Game() fires a listener on current player's value change in DB, then print the choice and score of the game on UI.

function initPlayer1Game(){
    database.ref("players/"+my_key).on("value",function(snapshot){
        var data = snapshot.val()
        if(data !== null){
            if(!in_game){
                $("#player1_name").text(data.name);
                printChoice("#player1_choice");
                printScore("#player1_result",my_win,my_lose,my_tie);
            }
            in_game = true;
        }
    })
}

handlePlayer1Offline() is used to remove current player's data from database, and this could help to automatically clean up the database.

function handlePlayer1Offline(){
    database.ref("players/"+my_key+"/online").on('value', function(snapshot) {
        if (snapshot.val()) { database.ref("players/"+my_key).onDisconnect().remove(); }               
    });
}

You can find the source code here:

https://github.com/gugucode/RPS-Multiplayer

Learn more about the Firebase database JavaScript SDK:

https://firebase.google.com/docs/reference/js/firebase.database

Step 6:

Use Firebase Hosting service to host your RPS-game, follow below steps:

// Install the firebase CLI
npm install -g firebase-tools

// Make a folder named rpg-project
mkdir rpg-project
cd rpg-project

// Login to your google account
firebase login


// Initialize your project and select the Firebase Hosting service with arrow keys to // go up/down and empty bar to select your service
firebase init

// Remove the default files inside public folder
rm -r public/*

// Clone your github repo to public folder
git clone <git_clone_your_project_path> public

// Run this command to deploy your application
firebase deploy

More detail can be found here:
https://firebase.google.com/docs/hosting/quickstart

Here is the URL to the game that has been deployed on Firebase Hosting:
https://rps-multiplayer-2c7aa.firebaseapp.com/

Happy coding ~~~~~~~~~`









No comments:

Post a Comment

IBM Cloud VPC Network Load Balancer -- Node.js SDK Examples

 What is Network Load Balancer (NLB)? Network Load Balancer works in Layer 4 and is best fit for business-critical and intera...