Build a Multiplayer Quiz Game With Vue.js
As developers, deploying applications and websites can be a pain point at times and we generally tend to prefer solutions that are easy and scalable.
Hosting solutions that require SSHing and having to make configurations and a million things to do before deploying can (and will) get tedious after a while. This is where Firebase Hosting comes in.
We’ll build a static website and deploy it to the web using Firebase Hosting. We are going to build a realtime multiplayer trivia game, the game is going to work like the popular multiplayer game QuizUp.
Here’s how the game is going to work. The questions are going to be gotten from the lyrics from Hamilton: An American Musical and users have to answer correctly the name of the character in the musical who sang that line. The game tests the user’s knowledge of Hamilton and users can play for as long as they like. See a demo below.
Our game will be built with Vue.js and will use Pusher’s Client Events and Presence Channels to make sure a user’s move is shown realtime.
What are Presence Channels?
Pusher’s Presence channels expose the additional feature of an awareness of who is subscribed to that channel. This gives developers the ability to build features like chat rooms, collaborators on a document and multiplayer games.
All Presence Channels must be subscribed with the prefix of presence-
and as with private channels a HTTP Request is made to a configurable authentication URL to determine if the current user has permissions to access the channel.
What are Client Events?
Client events are simply a way in which events can be triggered directly from the client-side as opposed to triggering from the backend server. Client Events are used in instances where some actions may not need validation or persistence and can go directly via the socket to all the other clients connected to the channel.
In our case, we use the Client Events to update a user on the current score of the other user playing the game.
Client Events have a number of enforced restrictions to ensure that the user subscribing to the channel is an authenticated user:
- Client events must be enabled for the application. You can do this in the Settings tab for your app within the Pusher dashboard.
- The user must be subscribed to the channel that the event is being triggered on.
- Client events can only be triggered on private and presence channels because they require authentication.
- Client events must be prefixed by
client-
. Events with any other prefix will be rejected by the Pusher server, as will events sent to channels to which the client is not subscribed.
You can read more on Client Events by going through the documentation.
Setting Up Pusher
Log in to your dashboard (or create a free account if you don’t already have one) and create a new app. Copy your app_id
, key
, secret
and cluster
and store them somewhere as we’ll be needing them later. One more thing. In your dashboard, navigate to the App Settings tab and make sure the Enable Client Events checkbox is checked. This lets clients communicate directly with each other.
Initializing the Vue.js Application
Vue.js is the preferred JavaScript framework to build the game because of its popularity and low barrier to getting started. There are some Vue.js tutorials on Pusher which you can read here, here and here.
We’re going to be using the vue-cli to scaffold a Vue.js project. The vue-cli
is a simple CLI for scaffolding Vue.js projects. It ships with many templates like webpack, browserify, pwa and simple. We’ll install vue-cli
and then use it to bootstrap the app using the webpack template, with the following commands:
npm install -g vue-cli
vue init webpack hamiltonlyrics
This creates a Vue.js app inside the a folder titled hamiltonlyrics
. Navigate into the folder and run the command npm run dev
to see the Vue.js application.
Setting up a Node.js Server
As explained above, Client Events require authentication to make sure a user is subscribed to the channel. Therefore, we are going to create a Node.js server so that Client Events can have an authentication route.
Let’s install the modules we’ll need for the Node.js server.
npm i express body-parser pusher
In the root of the project directory, create a file named server.js
and type in the following code:
In the code block above, Pusher is initialized with the dashboard credentials. The /pusher/auth
route is also created.
Now we can simply run node server.js
and the Node.js app should be up and running. Before we go on let’s add the command above to the existing scripts
object in the package.json
file so we don’t have to type in the command every time. Open up the package.json
file and edit the dev
line inside the scripts
object with the one below.
"dev": "nodemon server.js & node build/dev-server.js"
Building the game
Let’s get started on building the game. We’ll be working with two files throughout the course of this tutorial, a Home.vue
file and a ChannelDetails.vue
file.
Navigate to the components
folder inside the src
folder and create a new file called ChannelDetails.vue
. This will contain the JavaScript code that establishes a connection to Pusher from the client side. Open the file and type in the following code:
If you use ESLint, you should be getting a warning that the Pusher JS library has not been installed. That can be installed by running this command npm i pusher-js
. So what’s happening up there?
Firstly, Pusher is imported and a connection is established using credentials like APP_KEY, and CLUSTER. An authEndpoint is added to the Pusher instance. The authEndpoint is the endpoint Pusher uses to authenticate users.
Secondly, there are two functions above which are being exported. The first function getPresenceID()
checks the address bar of the browser for URL parameters and then appends presence
to the result. This is done so that the channel name will always have a prefix of presence-
since we are using Presence channels.
The second function uses the result of the getPresenceID()
function and uses it to subscribe to a channel (a Presence Channel to be specific).
The next thing to do is to start writing code for the game itself. Open up the App.vue
file inside the src
folder and make sure its content is similar to the code below:
Navigate to the src/components
directory and you should see a Hello.vue
file. You can either delete that file or rename to Home.vue
as we will be needing a Home.vue
file inside the components folder. Open up the file and type in/replace with the code below:
In the code block above, we set up the foundation for the game and how it’s going to work. Inside the <style>
tag and inside the <script>
tag, there are a couple of functions that we will need to create and add logic to.
Let’s take a look at the functions we need to create.
fetchData()
This function is called inside the created
hook and that means it will always be called whenever the instance has been created. Let’s write the code for this function.
getUniqueId()
This function simply generates random alphanumeric characters and adds a prefix of id=
to the result.
getUniqueId () {
return 'id=' + Math.random().toString(36).substr(2, 8)
}
checkPresenceId()
This function checks the address bar of the browser for URL parameters, in this case, any parameter that starts with ?id=
prefix and then returns the alphanumeric character at the end of the prefix. For example, this URL https://hamilton-lyrics.firebaseapp.com/#/?id=agbew0gz
will return agbew0gz
.
checkAnswer()
This function is used to check if the answer chosen is correct or incorrect. If the chosen answer is correct, 10 points will be added to the current score and if the answer is incorrect, 10 points will be deducted. The score is also sent to other subscribers of the channel via the channel.trigger()
function. At the end of it all, a new question is gotten via the getNewQuestion()
function.
getRandomQuestions()
This function is used to select questions randomly from the lyrics
array that holds the various questions. It takes in two arguments, array
and count
. array
would be the array we are trying to pick a random item from (lyrics
) and count
is the number of item to be chosen (1 item). This function is called in the getNewQuestion()
function below.
getNewQuestion()
This function is used to get a new question for the game. It utilizes the getRandomQuestions()
to get a new random question and sets it to the question
variable. It also uses the question’s data in the question
variable to initialize the various data instances.
We are done with the functions. Let’s create the template
tag and write the HTML code that will display the view for the game.
In the code above, we enclose everything in a transition
tag with an attribute of fade
. There are two div
sections that display conditionally. The div
tag with a class of home
is shown when there’s just one player online and the div
tag with a class of play
is only shown when two players are online.
At the end of it all, your Home.vue
file should look like this.
Setting up Firebase Hosting
Now that our application is ready and working well, let’s deploy the application using Firebase Hosting.
Getting started with Firebase Hosting is straightforward. Go over to console.firebase.google.com and create a new account or sign in if you already have an account.
Since this is a platform hosted by Google, you’ll need a Gmail account to be able to sign up and use the Firebase Console
Your dashboard should look like this (if you’re a new user). Let’s add a new project by clicking on the Add Project button.
That opens up a modal box that asks you to give your project a name and also choose your region. Once that’s done, you should be redirected to the project’s dashboard which looks like this.
The dashboard menu on the left shows all the Firebase services you can use in your application. Before we start deploying apps with Firebase Hosting, we need to install the Firebase CLI using npm.
npm install -g firebase-tools
If you’ve previously installed Firebase command line tools, run the install command again to make sure you have the latest version. Once the Firebase CLI has been successfully installed, we can deploy apps to Firebase Hosting with a single command.
Next step is to sign in to Google from the terminal so Firebase knows which account to use. Run the command firebase login
in your terminal. This process takes you to a login page in a browser where you enter your Google credentials and you are then logged in. Now Firebase is installed on our computer and we can begin deployment.
Preparing the Vue.js app for deployment
Now that we are done with the development of the app, it’s time to deploy the application to production via Firebase Hosting. How exactly do we do that? First of all, we need to build the Vue.js app for production and then run the Firebase deploy command. Let’s get started on that by running the command below.
npm run build
The command above helps to minify JS, HTML, and CSS. All static assets are also compiled with version hashes for efficient long-term caching, and a production index.html
is auto-generated with proper URLs to these generated assets.
Once the command is done with its process, the production-ready app can be found in the dist
folder. That is where the firebase deploy
command will be used.
Deploying to Firebase
We’ll need to initiate Firebase for this project, specifically inside the dist
folder. So run the command firebase init
. That command prompts the following:
- You’ll be prompted to choose which of the Firebase CLI feature you want to use, choose Hosting.
- You’ll be prompted to associate the current project directory with a Firebase project. Choose a Firebase project or create a new one.
- You’ll be prompted to type in the name of the folder you want to use as a public directory. This public directory is the folder (relative to your project directory) that will contain Hosting assets to be uploaded with firebase deploy. In this case, the name of the folder is
dist
. - You’ll be prompted to choose whether to configure the project as a single-page app. Choose Y.
The initialization process should be completed and we can run the firebase deploy
command now. When the deploy process is done, a live URL will be generated automatically by Firebase, in this case, hamilton-lyrics.firebaseapp.com. Firebase allows you to connect a domain to your Hosting instance so you can use a custom domain for your applications.
Conclusion
In this tutorial, we learnt how to deploy static pages to Firebase Hosting and making it realtime by using Pusher. We saw how to implement Pusher’s Presence Channels by using it to identify two different users online and then using it to build a multiplayer game. We also learnt how Client Events work, how to trigger events from the client side as opposed to triggering from a backend server.
Firebase offers a slew of services that can help you to build apps faster and you can read about them on the Firebase site.
If you want to go through the source code for the game above, you can do that on Github. You can also see the live demo at hamilton-lyrics.firebaseapp.com.
This post first appeared on the Pusher blog.