1
\$\begingroup\$

I'm building this game mostly because I want to experiment with Node.js and Socket.io, and the game is more like a proof of concept.

To start with, I have a 2D grid system as the game map.

_________________________________________.
|____|____|____|____|____|____|____|____|____|
.    
|____|____|____|____|____|____|____|____|____|
.
|____|____|____|____|____|____|____|____|____|
.    
|____|____|____|____|____|____|____|____|____|
.
|____|____|____|____|____|____|____|____|____|
.    
|____|____|____|____|____|____|____|____|____|
.
|____|____|____|____|____|____|____|____|____|
.    
|____|____|____|____|____|____|____|____|____|
.
|____|____|____|____|____|____|____|____|____|
.    
|____|____|____|____|____|____|____|____|____|
.
|____|____|____|____|____|____|____|____|____|
.    
|____|____|____|____|____|____|____|____|____|
.
|____|____|____|____|____|____|____|____|____|
.    
|____|____|____|____|____|____|____|____|____|.

Each position with values:

0: empty
1: wall - can not be destroyed by explosion 
2: obstacles - can be destroyed by explosion
3: bomb
4-9: some powerups
10>=: the id of player

CLIENT-SIDE

I'm not planning to have any game logic happen on the client side, so the client simply send left, right, up, down and plant a bomb command to my server. There is however, some simple check that happen on the client side - 1. check that there's no wall at the direction the client is moving to; 2. the client didn't plant a bomb in the last 3 seconds.

The client also receives the state of the map as a 2d array and knows how to draw everything using that info.

SERVER-SIDE

Main game logic happen on the server side, which includes updating the position of player, calculating the damage of bomb explosion - destroy stuff in the range, except walls and space behind walls

Questions:

  1. When the player is moving, he won't see himself moved until he gets the data back from server that updates his position. So I worry this delay may affect user experience, is it better that I move his position on his browser right away, and only update other players' position using info received from server, that means his own movement is rendered away, while his position info is sent to server.

  2. When rendering everything, it's simple to implement that whenever anything on the map move or change, redraw everything with the new data. Is that a waste? Can I only update things that change, for example, a player move right 1 position, nothing else changed on the game map, do I still have to redraw everything? I think I'm going to use Canvas to render.

  3. Please feel free to comment or answer if you think there are places I can improve or I simply thought wrong, thanks!

\$\endgroup\$

closed as too broad by congusbongus, Tom 'Blue' Piddock, Engineer, Seth Battin, Alexandre Vaillancourt Nov 14 '15 at 14:09

Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • \$\begingroup\$ This question seems to be about client-side prediction as well as dirty-region rendering optimisation. Could you pick just one? \$\endgroup\$ – Anko Oct 7 '15 at 10:10
  • 2
    \$\begingroup\$ Also, have you tested and found your naïve solutions to be too slow? Rules of program optimisation: ① Don't. and ② Don't yet (experts only). Unless you're academically interested in these optimisations, you may be shooting your future self in the foot here. \$\endgroup\$ – Anko Oct 7 '15 at 10:16
1
\$\begingroup\$

1.

You will need client side prediction here. Basically, as you said, your client will send the actions performed on his side to the server and instead of waiting for the server to send his new calculated position, it will predict them on his own side. In general, the client and server run the same code for a particular action, so basically for a MOVE_RIGHTa client would perform, the same moving logic will be run on both client and server.

When the client receives a new game state from the server (containing the actual position of this particular client on the server), it should set his position to the one in the game state so the client stay in sync with the server.

Lag between client and server can makes things a bit more tricky though. Imagine the situation where there is 150ms of lag between the client and the server. Client send MOVE_RIGHT action at t = 0 and instantly predict the result and move 5 units right (client is at X = 5 after prediction). The action will take 150ms to reach the server (due to lag) but the server keep sending game states regularly (let's say one game state every 20ms). Here is how the timeline looks like on the server:

 1. t = 20 => Server send a game state with the client position (X = 0)
 2. t = 40 => A new game state is sent (X = 0)
 3. ... (X = 0)
 4. t = 150 => The action finally reaches the server and is beeing processed (X = 5)
 5. t = 170 => Server send a game state with the updated client position (X = 5)

Here now the timeline on the client (keep in mind, 150ms lag between client and server)

 1. t = 0 => Send MOVE_RIGHT action and predict the result (X = 5)
 2. t = 170 => A game state is received, client updates his position based on the position in the game state (X = 0) 
 3. t = 190 => Same as step 2
 4. ... (X = 0)
 5. t = 300 => Finally a game state is received reflecting the client move (X = 5)

I hope you can see the problem now. If the client performs an action at t = 0, the server will process it a t = 150 and you will only receives a game state reflecting this action at t = 300. So basically, you will move your client 5 unit right at t = 0 (X = 5), snap it back to X = 0 at t = 170 and finally move it 5 unit right again at t = 300, which is of course unacceptable and will make your game unpleasant to play or even unplayable.

An easy way to overcome this problem is to keep track of unprocessed action on your client. When the client send the MOVE_RIGHT action, predict it and then store it with some kind of id. Your server should also send the id of the last action he processed with each game state. So now, when you receive a game state on the client, you can determine which actions are not yet processed on the server and reapply them on the client.

The problem is very well explained in this article: http://www.gabrielgambetta.com/fpm2.html

2.

Your server should only include what needs to be updated in the game states it sends. If a player has not moved since the last sent game state, no need to include it. You could also use delta compression to reduce the amount of data you send over the network.

About the rendering, i'm not so sure, only render what is visible on screen (i don't know if want to implement scrolling).

Ho, and of course: https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.