Press enter to see results or esc to cancel.

Tutorial : Creating a basic multiplayer game with Phaser and Eureca.io

The goal of this tutorial is to show you how to create basic multiplayer HTML5 game. I'll use Phaser for game developement and Eureca.io for client/server communication. for this tutorial I suppose you already have some knowledge about HTML5 game developement (with Phaser in preference) I also suppose that you have some knowledge about nodejs and that you already installed it. The game code I'll use is based on Tanks example game  from phaser website.   This video shows the final result
  let's start 🙂  

First step : refactoring the code

Some modifications and simplifications was made to make it suitable for multiplayer. I factorized player and enemy tanks code in a class named Tank (this is the renamed EnemyTank Class from phaser example code) since in multiplayer mode enemy tanks are just remote players. creation and update code was moved to Tank class. also added a Tank.kill method to remove a tank from game scene and moved the fire() code to Tank.fire   I also removed the damage handling stuff for simplification, so shooting other tanks will never kill them. one last change consisted in the way player Input is handled. the example code use phaser.input namespace directly (through game.input.keyboard.createCursorKeys() ) but in our case, the client should not handle any input directly, we'll see why later. so I created an Tank.input object and Tank.cursor Object to handle player inputs. and this is the code of modified update() function     you can download the refactored code here to help you follow next tutorial steps.

Download refactored Tanks Game code     Now that we have a simple code that work, let's transform it to a multiplayer game.

I'll use Eureca.io, an RPC library I developed for internal needs, and decided to open source it (source code available here https://github.com/Ezelia/eureca.io) the same principles here apply to any other networking library (socket.io, engine.io ...etc) but you'll see how Eureca.io makes things simpler 🙂
 

The web server

We will start by creating a basic web server for our game. here we'll install express library for nodejs, to make file service simpler, and it's compatible with eureca.io. express will also help you if you are building some webpages for your multiplayer game (it can handle dynamic webpages, sessions, cookies, forms ...etc)   create a server.js file on the root directory of Tank game, and edit it with the following code now start the server with the following command   open a browser and navigate to : http://localhost:8000/ if your Tank game is working you're good for the next step or you can simply download the code here  🙂 Download Tanks Game Step 1 code  

Installing and preparing eureca.io

Now let's start playing with Eureca.io Eureca.io can use either engine.io or sockjs as network transport layer, by default, engine.io is used. to use eureca.io with the default configuration we'll need to install eureca.io and engine.io   Now we'll modify the server code to add eureca.io stuff before : server.listen(8000) we instantiace eureca.io server and attach it to the HTTP server with the following code then we add some event listeners to detect client connections and disconnections in the client side we'll also make some modification first add the following line to index.html, before tanks.js script this will make eureca.io available to the client. now edit tanks.js file and add the following code at the beginning what we do here is creating a client initialisation method "eurecaClientSetup", which instantiate eureca.io Client and wait for the client to be ready, then call game creation method (create() ) the create() methode was initally called by Phaser.Game() instantiation method will modify this line to it call eurecaClientSetup
important : if you create a multiplayer game, you usually need to ensure that the server is available before starting the game code, this is what we are doing with eurecaClientSetup
one last thing. you may noticed the ready variable set to false by default, this flag allow us to know if client/server initialisation is done. and the game created. we use it to prevent phaser to call update methode before create(). so we need to add the following to update() method   you can download the resulting code here : Download Tanks Game Step 2 code run the server.js again (node server.js) and navigate to http://localhost:8000/ the game should start and you see that the server have detected the client connection. now refresh the page and you'll see that the client was diconnected then connected again. if this is working, we are ready for the next step.  

Spawn/Kill remote players

For our basic multiplayer game, the server need to keep track of all connected clients. to distinguish every client, we'll also need to have some uniq identifier for each player (we'll use a unique ID generated by eureca.io) this unique id is shared between client and server ; it allow them to synchronize players data and make correspondance remote clients and Tanks. so the implementation will be as follow.
  • when a new client connect, the server will create a uniq id (eureca.io session ID is used here)
  • the server send this uniq id to the client
  • the client create the game scene with player's Tank and assignate thie unique ID to its Tank.
  • the client notify the server that everything is ready in the client side (we'll call this a handshake)
  • the server get the notification and call client Spawn method for each connected player.
  • the client spawn a Tank instance for each connected player
 
  • when a client disconnect, the server identify it and remove it from the list of connected clients
  • the server call Kill() methode of all connected clients
  • each client remove the Tank instance of disconnected player
  And this is how we implement this

Client side

Eureca.io instances have a special namespace called "exports", all methods defined under this namespace become available for RPC. we'll see how to use it. for this we need to modify eurecaClientSetup method in the above example we have three methods that'll be callable from the server side : setId, kill and spawnEnemy . Note that the client is calling a remote server function : eurecaServer.handshake() .  

Server side

the first thing it so tell Eureca.io that client methods (setId, kill and spawnEnemy) are trusted client functions, otherwise eureca.io will refuse to call them in client/server developement we should never blindly trust the client. the following code tells Eureca.io to trust those methods and create a clientList object that'll hold clients data Now let's modify onConnect and onDisconnect methods
Note how the server call the remote client functions :   remote.setId(conn.id)   and   remote.kill(conn.id);
    if you remember, the client also call a server side method, and here is how we declare it   Now start the server and open a first browser window on http://localhost:8000/ move the tank a little and open another browser window on http://localhost:8000/ in the first window you should see a tank spawning . close the last window and the tank will disapear. this is pretty good hah 🙂 but still not a multiplayer game. the Tank movement is not reaplicated yet, and this is what we'll do in the next step.   by the way, here is the full code of the above step 😀 Download Tanks Game Step 3 code

 

Handle input / Synchronize states

In a multiplayer game, the server need to control client states, the only trusted entity is the server. (there are some other variants like P2P games ... but we'll not discuss them here 🙂 ) in an ideal implementation of client/server game, both client and server simulate the movements, then the server will send state data to the client which will correct/compensate the local positions. in our example we will only synchronize a minimum set of information and "trust" the client side simulation. this is how it'll work.
  • when the player issue an input (movement or fire), it'll not be handled directly by the local code.
  • instead, we'll send it to the server, the server will loop through all connected clients and send them the client input
  • each client will apply this input to the client side copy of the Tank.
  • the Tank handle the input sent by the server as it was issued by a local input
in addition to this, each time an input information is sent, we will also send information about Tank position, this information will be used to synchronize Tank states with all connected clients. let's write the code to handle this.

Client side

We'll first edit eurecaClientSetup method and add the following exported method remember : methods under exports namespace can be called from the server. updateState method will update Tank.cursor with the shared player input but will also correct the Tank position and angle.   Now we need to handle this in the Tank.update method edit Tank.prototype.update and replace the following line with this code here we first detect if the local player made an input (mouse click or keyboard left/right/up) if so, instead of handling it directly we send it to the server throught eurecaServer.handleKeys the server side handleKeys method will send back the input to all connected clients as we'll see bellow.  

Server side

First we need to allow the newly declared client method (updateState)   then we declare handleKeys method   and one little modification to the existing handshake method   if you followed all those steps (or downloaded the final code from the link bellow 😀 ) you can start the server and open two or more windows. Now when you move a Tank in one client or launch projectile, it also move in other windows 🙂

What next?

You have now a basic code and notions of multiplayer game. as an exercice you can try to handle damages, kill and respawn, you can also to handle position synchronization better with smooth lag compensation.
if you liked this tutorial share it and of course, comments and suggestions are welcome   Download Multiplayer Tanks Game final code

Receive updates, free resources and more

Indie Gamedev newsletter
Receive curated list of resources specifically selected for indie game developers. including free graphics and music assets, tutorials, software ...etc
We respect your privacy
  • Alejandro toledo armas

    I cant download Tanks Game final code, error 404

  • Ahmed Hashem

    awesome tuts man thanks

  • Robert

    Tks bro! It really solved my problem… but… in the function bulletHitPlayer, how can i call the kill prototype function? i alread tried a lot of possibilities, like: tank.kill… tank.kill().. and ive no sucess :C

    • Ezelia

      as for movements, you don’t have to call tank.kill() directly.
      instead, you need to send an instruction to the server.
      then broadcast that instruction from the server to all clients.

      on the clients side, you need to find the killed tank, and call .kill() method for it.

      • disqus_Rx5kXnqN72

        how?

  • SuperMarco

    I have a quick question about the reaction time here. I didn’t tried your code yet (but I will apply to my future game soon enough :D).

    In the video, I could see a small delay about the position and action of the tank on the other client. Like its very small, but still here 🙂 . I was wondering if it was coming from the fact you have 2 browser open and you’re not focusing one or it always have this small delay ?

    Great tutorial btw 😉

    • Ezelia

      there is always lags when implementing networking stuff, this is a very basic tutorial which do not adress lag compensation.
      for simple scenarios it’s enought to make a multiplayer games, but if you need more accuracy, you’ll need to implement lag compensation in the client site 😉

      • Thomas Weissel

        hello,
        first i want to thank you for this tutorial. i was able to create a nice multiplayer game in an instant.. BUT…

        the mentioned lag is really killing me.. i ran it on a server and connected 4 clients to it and those clients are jumping from one position to another and sometimes back.. even the inputs of my own car (in my game players are cars) is somehow delayed.. changing the rotation sometimes feels like i’m holding down the cursor key for an additional second..

        do you have any tips on how to tweak performance here? (probably another tutorial based on this one??)

        and there is another question i have: if update() updates all tanks and every client is sending it’s current state and therefore also updating his player on my computer.. isn’t update called twice everytime? or even worse.. once for every connected client?
        in other words.. i update every client locally and then every client is again updated by a server call (updateState)

        is the server call asynchronous or does my update loop wait for it (the latter would cause huge fps drops.. (and sometimes it looks like it does ) )

        thank you!

  • Matthew D

    Tanks, helped a lot

  • Alex Tonkin

    I think there is a bug in your code in the handshake function. As more clients are added duplicate tanks are spawned in the previously opened clients. It seems that for every client added 2 more tanks are added to each previous client in a pattern. For example with 4 clients the most recently opened one will have 4 tanks, the next 6, the next 8 and so on.

    • Alex Tonkin

      I found another bug in your handlekeys function. It shouldn’t overwrite every single clients last state, only the client that is calling the update.

    • zx424

      change it to:
      if (i == myId || ( i in tanksList)) return;

  • Greg Malone

    Excellent tutorial!

  • disqus_Rx5kXnqN72

    can i ask if there is a video tutorial.. step-by-step for a newbie programmer like myself?

  • disqus_Rx5kXnqN72

    how many attacks does it need before one player dies? coz it does seem to have a kill method?

  • Tom

    I would love to see how you deal with server side variables. Maybe clients x,y could be stored on the server. That way, when a client comes back, they will get put back in last known place.

  • Virenz Patelz

    For some reason i cant get the game to work when i host it on google drive. Do i need to change something?

  • Jack Northrup

    Nice. It started right up Working on a database to track scoring now.

  • Nick Rameau

    Hi there! I really liked this tut. I have a question tho: How would I handle multiple games? For example, I limit a server to 30 players, once there is 30 players in the server, I want to send the next player to a second server, and so on. How do I do that please?

  • kay17

    Super tutorial! I finally managed to get a multiplayer working 🙂 But how could I give different colors to the tanks, to make it easier to distinguish the 2 players? I tried to add a random tint to the tank sprite in the Tank constructor function, like so:

    this.tank.tint = Math.random() * 0xffffff;

    But I end up with different colors on the two browser screens. (so I have 4 different colored tanks in all)

  • MilanObrtlik

    Tank you for your work 😉
    Can you solve lags? It will be awesome 🙂