How to use Socket.IO and build your first multiplayer game!
kuberdenis

kuberdenis @kubeden

About: I am a "Senior DevOps Engineer" by job title, considering myself a futurist interested in the future of technology, and an educator by heart who loves to share about his findings. Let's connect on X!

Joined:
Jul 1, 2020

How to use Socket.IO and build your first multiplayer game!

Publish Date: Sep 28 '20
98 18

Prerequisites:

Must-haves

  • node.js
  • npm
  • express
  • socket.io
  • VS Code

Introduction

Backstory

If you read my other post you already know what we are going to build. If not - let me explain. We are going to build a version of ChrisOnCode's 'Crazy Buttons' lesson. We are going to create a button which when clicked, moves to a random location within the document. We are also going to make the movement real-time so other people see if there is somebody else clicking it.

What is socket.io

As stated by the developers themselves: "Socket.IO is a JavaScript library for realtime web applications. It enables realtime, bi-directional communication between web clients and servers. It has two parts: a client-side library that runs in the browser, and a server-side library for Node.js"

So basically it's a library that allows us to create realtime applications. An example of such is the .io games and the Facebook chat. I suggest you take a look at their official website. Checking this link could also help you understand how it works.

Now you know what we are going to build as well as with what.

Setting up the environment

As I am using Windows, I will be using Windows terms but if you're using another OS I am sure you will manage. Okay, we will start by setting up the environment. Create a new folder and name it The internet button. Open VS Code in the folder and create the following structure:
Folder Structure

Now we need to build the fundamentals of our application. Open a terminal in the directory and type

npm init
Enter fullscreen mode Exit fullscreen mode

Leave the values blank, or add your name and description - it's your choice. We also need to install nodemon so we don't have to restart our application each time we make a change. Do so with

npm install -g nodemon
Enter fullscreen mode Exit fullscreen mode

The last packages we need to install are express & socket.io

npm install --save express socket.io
Enter fullscreen mode Exit fullscreen mode

After all the package installation, your package.json should look similar to this:
package

Cool, we are ready and set. Let's get to work!

Building the app

Adding our variables

We will start with creating a server.js file inside our server folder. Now let's setup all the variables we need. We will start loading our modules first. Add the following 4 variables:

const path          = require('path');
const http          = require('http');
const express       = require('express');
const socketIO      = require('socket.io');
Enter fullscreen mode Exit fullscreen mode

Okay, now let's set-up the express server. We will first set our path to serve our HTML through the public folder we created:

const publicPath    = path.join(__dirname, '/../public');
Enter fullscreen mode Exit fullscreen mode

We also need to specify a port our app is going to run on. Let's go with 3000:

const port          = process.env.PORT || 3000;
Enter fullscreen mode Exit fullscreen mode

Now we call our express function with:

let app             = express();
Enter fullscreen mode Exit fullscreen mode

We then specify the http method to let HTTP connection in:

let server          = http.createServer(app);
Enter fullscreen mode Exit fullscreen mode

Lastly, we set up our socketIO connection:

let io              = socketIO(server);
Enter fullscreen mode Exit fullscreen mode

Our server.js file should have the following lines of code:

const path = require('path');
const http = require('http');
const express = require('express');
const socketIO = require('socket.io');

const publicPath = path.join(__dirname, '/../public');
const port = process.env.PORT || 3000;
let app = express();
let server = http.createServer(app);
let io = socketIO(server);
Enter fullscreen mode Exit fullscreen mode

Setup our functions

We need to set our express server to finally serve the content:

app.use(express.static(public path));
Enter fullscreen mode Exit fullscreen mode

And finally connecting to the port:

server.listen(port, ()=> {
    console.log(`Server is up on port ${port}.`)
});
Enter fullscreen mode Exit fullscreen mode

Cool, we are all set. Now go inside the public folder, create a simple index.html file and add something to it. I am going to create a blank HTML document and add an h3 tag containing "Welcome to the socket.io training!". Go to your browser and type localhost:3000 to verify everything is working.

Perfect. Let's advance!

Setting up the front-end

As this is a socket.io tutorial I'm not going to fall into details on how to set-up your HTML & CSS. Instead, I'm going to give you a link to the project without the socket.io part and we will build that instead. link

If you clone the project, keep in mind you have to create the folder server and add your server.js file. You also need to add app.js inside the public/js folder.

Socket.io

Variables

Okay, we already know what socket.io is and how it works. It is now time to make it work with our buttons. Insite public/js we are going to create an app.js file. We add our socket at the top

let socket = io();
Enter fullscreen mode Exit fullscreen mode

We get our starting section. It contains components, visible before we click the "Start" button and disappear when we start the game.

const startingSection = document.querySelector('.starting-section');
Enter fullscreen mode Exit fullscreen mode

And the 'Start' button...

const homeBtn = document.querySelector('.home-btn');
Enter fullscreen mode Exit fullscreen mode

Finally, our 'crazy' button. The one that moves:

let crazyButton = document.getElementById('crazyButton');
Enter fullscreen mode Exit fullscreen mode

Socket.io server connection

Go to the server/server.js file and open a socket.io connection with the following code:

io.on('connection', (socket) => {
    console.log('A user just connected.');
    socket.on('disconnect', () => {
        console.log('A user has disconnected.');
    })
});
Enter fullscreen mode Exit fullscreen mode

This is a built-in function. Whenever a new connection is made, the code within it will be executed. We include another built-in function disconnect which is self-explanatory.

We can test this by starting nodemon (nodemon server/server.js) and browsing to localhost:3000. Open the terminal in VS Code and check if a message is being logged.

Start Game real-time

Let's create the functionality for the "Start" button. We are going to hide the .starting-section components and also make it real-time so they hide for other players as well. Navigate to app.js and add a click event listener to the start button:

start button.addEventListener('click', () => {

})
Enter fullscreen mode Exit fullscreen mode

Inside our event listener, we must emit a message to the socket.io server with socket.emit('startGame');:

startButton.addEventListener('click', () => {
    socket.emit('startGame');
});
Enter fullscreen mode Exit fullscreen mode

Now on the server side(server.js), we must create a 'listener' for that message:

socket.on('startGame', () => {

})
Enter fullscreen mode Exit fullscreen mode

We emit a message back to all the connected clients:

socket.on('startGame', () => {
    io.emit('startGame');
})
Enter fullscreen mode Exit fullscreen mode

We then process the 'message' from the server in our app.js:

socket.on('startGame', () => {
});
Enter fullscreen mode Exit fullscreen mode

and we call the function hideStartButton():

socket.on('startGame', () => {
    hideStartButton();
});
Enter fullscreen mode Exit fullscreen mode

Finally, we declare our hideStartButton function:

function hideStartButton() {
    startButton.style.display = "none";
    crazyButton.style.display = "block";
    startingSection.style.display = "none";
}
Enter fullscreen mode Exit fullscreen mode

Now we test if everything is working in localhost:3000:
9b72a53939f52dd58052583a273a1851

Move the button real-time

For this part everything is almost the same with only one difference - we must pass data from our app to the server, process it, and return it to each connected client.

We add a event listener to our crazy button & emit a message containing an object with two values - offsetLeft & offsetTop, which are a Math.random multiplied by the innerWidth & innerHeight of our window - the button's clientWidth & clientHeight:

crazyButton.addEventListener('click', () => {
    socket.emit('crazyIsClicked', {
        offsetLeft: Math.random() * ((window.innerWidth - crazyButton.clientWidth) - 100),
        offsetTop: Math.random() * ((window.innerHeight - crazyButton.clientHeight) - 50)
    });
})
Enter fullscreen mode Exit fullscreen mode

The server then receives these values under the form of 'data' variable & emits them back:

socket.on('crazyIsClicked', (data) => {
    io.emit('crazyIsClicked', data);
});
Enter fullscreen mode Exit fullscreen mode

Our app.js file then receives the data and input it in the function, which moves the button:

socket.on('crazyIsClicked', (data) => {
    goCrazy(data.offsetLeft, data.offsetTop);
});
Enter fullscreen mode Exit fullscreen mode

We create our goCrazy function:

function goCrazy(offLeft, offTop) {
    let top, left;

    left = offLeft;
    top = offTop;

    crazyButton.style.top = top + 'px';
    crazyButton.style.left = left + 'px';
    crazyButton.style.animation = "none";
}
Enter fullscreen mode Exit fullscreen mode

And we test:
fde568eb7135dda0b81455054cc4eb37

Cool, we are all done!

Conclusion

Today you learned what socket.io is, how to pass data, and how to emit & listen for messages. I hope this was helpful and you learned something today! Full project available at my website.

Make sure to check out my other post related to this - The JSourney: Learn with projects, not videos!. I explain why building projects is a better way to study, instead of watching videos all day.

Comments 18 total

  • Bobby
    BobbySep 28, 2020

    Great post! Love it 🚀

    Sounds like a perfect idea for a first project 🙌

  • Nida Shaikh
    Nida ShaikhSep 28, 2020

    This is so cool! I was just thinking about making something multiplayer and this post popped right up on my feed. Thanks for this implementation!

    • kuberdenis
      kuberdenisSep 28, 2020

      Hey there, you're most welcome!!

  • Adrien Auxent
    Adrien AuxentSep 29, 2020

    Hey, just wanted to say I got stuck on that line : "app.use(express.static(public path));"
    Had to rename public path to publicPath.
    also :
    socket.on('startGame', () => {
    io.emit('startGame');
    }) gives me an error asking me what is socket.
    So I changed socket with io, cause that's a variable.
    It took me reading the socket.io doc to find out I had to place this part inside the connection log part :
    io.on('connection', (socket) => {
    console.log('A user just connected.');
    socket.on('disconnect', () => {
    console.log('A user has disconnected.');
    })
    socket.on('startGame', () => {
    console.log('Game started');
    io.emit('startGame');
    })
    });

    I also had to add the event on home button, and a function :
    app.js:
    socket.on('home', () => {
    showStartButton();
    });
    function showStartButton() {
    startButton.style.display = "block";
    crazyButton.style.display = "none";
    startingSection.style.display = "block";
    }
    server.js :
    socket.on('home', () => {
    console.log('home button pressed');
    io.emit('home');
    })

    A few missing informations, but thanks for the tuto anyway! It works now.

    • kuberdenis
      kuberdenisSep 29, 2020

      Hi there, I'm glad you figured it out!

      A few notes - on the line with changing the socket to io, maybe you got something wrong with setting the app.js. You should have "let socket = io();" in the very beginning of the app.js file. For the buttons missing styles, I have included a GitHub link with the HTML & CSS.

      • Adrien Auxent
        Adrien AuxentSep 29, 2020

        The socket part was on the server side.
        What I got wrong was I didn't realise I should place the listener inside the "io.on('connection', (socket) => {})" , and not after it.
        And yeah, I took the github files for HTML and CSS. I am glad I didn't have to write that one down line by line. But there was still some lissing JS lines to have a working home and start button. I could ifigure it out from your exemple though.

        • kuberdenis
          kuberdenisSep 29, 2020

          Aah, I see. Anyway, you figured it out, which is great! Also, if somebody else stood upon the same problem, they will have the solution, so thanks for the comment!

  • Hòa Nguyễn Coder
    Hòa Nguyễn CoderOct 2, 2020

    Very good! Thankd you!

  • Andrew Baisden
    Andrew BaisdenOct 13, 2020

    It looks quite easy to implement which is great I could see someone creating a game like Among Us.

    • kuberdenis
      kuberdenisOct 16, 2020

      Maybe somebody is working on that... but shhh don't tell anybody! 👀👀👀

  • Abdur-Rahmaan Janhangeer
    Abdur-Rahmaan JanhangeerJan 4, 2021

    I think you missed braces

    (The JSourney: Learn with projects, not videos!)[dev.to/denislav__/the-jsourney-lea...]

  • OkkarMin
    OkkarMinMay 20, 2021

    Hey Denislav,

    I got inspired and tweaked the content a little to create a workshop/content for incoming freshmen. I would like to credit you and is there any preferred way you would like us to credit you? 😊

    crazyworkshop.yeowys.com/

    • kuberdenis
      kuberdenisJun 8, 2021

      Hey there, I'm glad you got inspired to include this in your own website! Feel free to credit me in the footer by linking to my Twitter profile (@asciiden ). Thanks!

  • Ghis
    GhisSep 21, 2021

    Hi,
    The article is a good idea but it is incomplete, there is some mistakes and few things that could be improved imo. I followed it but encountered some errors and things not written in the article. Here is some:

    • You should put a link to a github or zip containing the base structure of the empty project so we don't have to manually create it by hand.
    • You don't define the startButton variable. We have to find it by ourselves. let startButton = document.getElementById("startButton");
    • Some variables are weirdly written: "start button" instead of "startButton" and "public path" instead of "publicPath".
    • You don't explain how to use the Home button even if you make a gif with it working.

    • The link to a demo at the end does not work anymore.

    • You should put a link to a github or zip containing the final structure of the project.

    • The HTML you linked from another github uses bootstrap which make the custom cursor not working on buttons.

    Sincerely yours,
    Ghis

    • kuberdenis
      kuberdenisSep 22, 2021

      Hey Ghis! Thanks for commenting on this. I will make sure to update it asap!

  • khkb
    khkbOct 8, 2021

    Hlo sir ,
    If we have 2 games in our frontend then how to setup socket server.

Add comment