Jerorx

How to make a multiplayer online game with Phaser, Socket.io and Node.js

Recommended Posts

Hi,

I've been working on multiplayer online experiences with Phaser, Node.js and Socket.io recently. I thought that it might be interesting to make a tutorial detailing how to make a very basic multiplayer game with these tools, so here it is : How to make a multiplayer online game with Phaser, Socket.io and Node.js .

As I said, the game (which can be played here) is very very basic: you click on the small map and your character moves to where you clicked. The movements of the other players (if any) are displayed in real-time. No animations or collisions or whatever, the focus is on the networking aspect.

Feedback is more than welcome, as this is my first tutorial ever. If you find it interesting and would like me to make follow-up tutorials on some aspects, don't hesitate to ask!

Jérôme

Share this post


Link to post
Share on other sites

I am actually undergoing a similar network setup now, for a small project. I would appreciate more details on getting new players sprites added to the map of each client and updating their position.

Share this post


Link to post
Share on other sites

Nice example,I know it's just to demonstrate how simple it's setup a simple multiplayer game. 

But I'm afraid there is a slight problem with such concept. Especially in case the player position really matters. (for ex. in player combat.). 

Let's say you have a player A and B.

Player B is on a slower network and so are the responses from their network

  • Player A sends message telling server that he's moving to pos.x , pos.y
  • Server receives the message (20 ms later)
  • Broadcasts the information to all connected clients 
  • Player A  receives the message (50 ms later)
    • proceeds with executing the movePlayer method.
  • Player B receives the message (200 ms later). 
    • proceeds with executing the movePlayer method.

Now it's clear that the Player A will arrive at totally different time on Player B side as it will on Player A client.

So the question being, how do we solve this? Should I send the time when the action was performed

and calculate the elapsed time after receiving the message from server? And then try to predict the current position

of the player based on the elapsed time? 

Share this post


Link to post
Share on other sites

@kabuto178 : I invite you to have a look at the source code, and more particularly at client.js, which processes the messages from the server, and game.js, which contains the Phaser code. When a new player connects, the server sends the message 'newplayer' to all clients, along with the id and coordinates of the new player. This is handled in client.js by

Client.socket.on('newplayer',function(data){
    Game.addNewPlayer(data.id,data.x,data.y);
});

In game.js, Game.addNewPlayer() is defined :

Game.addNewPlayer = function(id,x,y){
    Game.playerMap[id] = game.add.sprite(x,y,'sprite');
};

So it boils down to using Phaser's game.add.sprite, using the coordinates sent by the server. (Game.playerMap is a map to organize the sprites by id).

Similar methods are used to update the position upon receiving a 'move' event from the server. In client.js:

Client.socket.on('move',function(data){
    Game.movePlayer(data.id,data.x,data.y);
});

And in game.js:

Game.movePlayer = function(id,x,y){
    var player = Game.playerMap[id];
    var distance = Phaser.Math.distance(player.x,player.y,x,y);
    var tween = game.add.tween(player);
    var duration = distance*10;
    tween.to({x:x,y:y}, duration);
    tween.start();
};

Where a basic tween is used to move the sprite. Let me know if this is helpful or not.

@FakeWizard: this is a good point indeed. Actually, I had to solve that problem for a game I just finished, which I will release in a few days. I'm also currently writing an article with a section precisely about this, which should come out at the same time. Both will be published on the same website as this tutorial.

The first solution I used was the one you mention, by associating timestamps to movements. But it turned out to be a bit problematic, because timestamps are not universal, they can vary wildly from one machine to another (if you can, open a browser on two different computers side by side, and in the console type console.log(Date.now()); you should see different values). It worked as long as I was testing on my machine, but once online it broke down.

I ended up simplifying this, and instead of using the timestamps, I only used the latency of the clients, which is the key factor here. Once you keep track of the latency, you can use it as follows:

  • Player A sends message telling server that he's moving to pos.x , pos.y
  • (In my implementation, since the environment is fixed, A doesn't have to wait the response from the server to move ; it moves immediately, and will be adjusted only if the server replies that the move was illegal, which can happen only by attempting to cheat. It makes the game more responsive but doesn't change your point.)
  • Server receives the message X ms later. The server has an estimate of X (= latency of player A) and stores it along the move request.
  • Server broadcasts the information to all connected clients; to each, it sends the information that A has moved, along with the latency X of A, + the latency Y, Z, etc. of each receiving client
  • Player B receives the message K ms later. If we consider that X was the latency of player A, and Y is the latency of player B, K = X + Y. The values of X and Y are estimated by the server and sent along the movement messages, so they are known by the client when he has to update position. Now, the position update is likely not instantaneous, to be smooth you are likely to use a tween or something. The duration of the tween can be adjusted to compensate for the delay K. If K is 150ms and the tween is supposed to last 400ms, the tween will end up lasting only 250ms, to make sure that on the screens of the two players, A's sprite arrives at his destination roughly at the same time. Typically, such changes in tween duration are not very perceptible; either the tween lasts a long time, and a difference of 150ms will be no difference, either it is short, and the tween will happen too fast anyway for a human observer to really perceive the difference.

Let me know what you think of this solution, I'm interested in feedbacks. Out of experience, it worked pretty well for my game in any case. Now if you make a fast-paced game such as an FPS or a MOBA, where very fast, short movements happen a lot, this solution might not be the best one (although with 200ms latency, players will be screwed no matter what in that kind of games). Dedicated solutions exist for this kind of games, but it's always relatively tricky and ad hoc.

If you use Twitter, I invite you to follow me to get notified when I release the article about this problem, it should interest you. If not, I'll notify you through here. ;)

Share this post


Link to post
Share on other sites

@Jerorx yeah, you're so right , the time stamp could vary from client to client. I wonder how come it didn't occur to me before :) ..The other solution indeed sounds less difficult to implement, although (IMHO) the ultimate solution for this kind of problem is to use position prediction algorithm. There is a great article about this - here 

Having said that, even with the best approach , the performance would still not be perfect. The whole communication between socket.io service and it's clients is done through TCP/IP.  Which is not recommended for real-time multiplayer games. It's not a big deal with few clients , but when you're building a game which could potentially grow up to thousands concurrent request per second , then your best bet would be to re-design your backend service to work in a cluster. So each cluster node could take care of a pre-defined number of clients.

If you're familiar with socket.io,  there is a great framework ( SocketCluster ) which can help you scaling your socket.io service both vertically and horizontally/

Share this post


Link to post
Share on other sites

@kabuto178 The problem would rather be the type and movements and the pace of the action, rather than the real-time aspect. You can have a look at Phaser Quest, which is the multiplayer online game I was referring to in my previous message. Similarly to BrowserQuest, it is designed to be an MMO-like, and the solution I discussed works well for this game.

@FakeWizard Good points.

Actually, having a tween execute the movement from point A to point B is some form of movement prediction: you assume that the player will follow the indicated trajectory until the end and render it accordingly. The trick is then to make sure that the timing of this rendering is correct!

Did you know that Blizzard's World of Warcraft uses TCP? It's true that UDP is often recommended for online games, but UDP and TCP both have pros and cons, and some AAA MMO's do use TCP apparently. I don't have a reference available here but I can try to post one later.

Indeed, to handle very big loads and scale well, eventually the back-end architecture has to change, even from the hardware point of view. Thanks for the pointer to SocketCluster. I still have some margin before any of my projects gather enough traffic that such improvements are necessary, so I admit I haven't looked into much of that yet, but you are right: eventually, any serious MMO project will have to resort to that.

Share this post


Link to post
Share on other sites

@Jerorx Well as far as I know, they'e using UDP for spatial calculation of game objects, for chat,mail,auction house they're using TCP , which makes sense cause It offsets way more safer and reliable communication than the UDP...The main problem with TCP in real-timei is that, when a packet is lost somewhere along the way, the connection is stall until re-transmission takes place. ... UDP on the other hand is just pushing the data from server to client and vice versa. If a packet is lost, it doesn't cause any delays, it will eventually arrive but it's up to the game client or server whether to process the out-of-date data or just ignore it. 

Also I've  just realized that Nagle's algorithm , is turned off by default in socket.io , which is always recommended to disable/turn off  if you're to use TCP in multiplayer games. 

There is still plenty of work ahead of me , and I'm really looking forward to see how it;s gonna all work ( or not) :) 

Another project worth checking is Incheon (Multiplayer game server based on Node.JS) http://incheon.gg/

Thanks again for sharing your thought with us! 

Share this post


Link to post
Share on other sites

Thanks for the pointer to Incheon, didn't know it, looks quite interesting!

@kabuto178 Keyboard-controlled movements would typically fall in the "fast-paced games" category, in which case the server would send the player coordinates multiple times per second, and the client would interpolate the sprite's position in-between. This is often done by not rendering the last update, but the one-before-last; this keeps the rendering slightly in the past but allows to cope with latency. Actually, this conversation made me think that I should make another tutorial similar to this one but for keyboard-controlled multiplayer games. That would be a good testing bed and would be useful for the discussion. I'll try to post that relatively soon!

Share this post


Link to post
Share on other sites

Hi all

Hello @Jerorx  

I doing follow http://www.dynetisgames.com/2017/03/06/how-to-make-a-multiplayer-online-game-with-phaser-socket-io-and-node-js/

your demo here: https://basic-mmo-phaser.herokuapp.com/

I how to i can fix when a Hero move use tween

For example:

 Click points A. with distance Hero to A is 100Km

Hero moving 

After a second Click points B with distance Hero to B is 50Km

  Hero movie to poins B but i see hero stop points A ( it continue move to A)

How to fix this?

Thank you.

demo phaser.png

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.