2
\$\begingroup\$

I am developing a tile-based online multiplayer game, but I am stuck. Players can move across the grid in the four cardinal directions, as can enemies, but two players/enemies cannot occupy the same tile at the same time. Positions of all players/enemies are synced for all clients.

My current implementation of movement: Clients send a 'request to move' to the server whenever they are stationary on a tile.

I have implemented client prediction. When a button is pressed to move, the client shows their character immediately moving in that direction, as opposed to waiting for confirmation from the server, preventing lag between player input and visible results.

The issue arises when the player attempts to move to a position that will soon be occupied. For example, the player presses up when an enemy is very close to entering the tile above the player (though they can't currently know that the enemy will choose that tile next). Locally this is confirmed and the upwards animation begins, but by the time the request to move up arrives at the server, the tile is no longer free, and the player is not moved up on the server.

This creates a situation where the player's local position is out of sync with that of the server. My current solution to this is snapping the local player back to the server's position when this happens, but this looks awful. It seems to be happening a lot, making the game nearly unplayable.

Is there a way around this? Any help would be very much appreciated, thanks.

Some other notes: I send updates from the server 10 times a second, which consist of every object's position (and other stuff). When a movement event is processed, the object's position is updated immediately, even though an animation follows.

\$\endgroup\$
2
\$\begingroup\$

Your prediction method has "coarse granularity" so to say: when prediction fails, big amount of movement is cancelled, which leads to jarring visuals.

In comparison with games in other genres (FPS, RPG, plaformers, etc), where movement prediction is used, movement is usually continuous. In case of prediction fail, this leads to relatively small amount of movement being reverted, which may be smoothed further with quick client-side interpolation.

This is fundamental "no free lunch" problem. If prediction fails, it has to be corrected, otherwise you'll get desync. Thus, either make movement more "fine-grained" (i.e. by using smaller grid), or get rid of prediction (wait for server response).

Your game seems more similar to RTS. AFAIK, in that genre it's more common to use deterministic inputs ("lockstep"). Sometimes it may be notices as input lag in multiplayer games. (Technical details here.)

Because lockstep is not trivial to implement and might not fit your client-server model, I'd stick with server confirmation. Though, don't ask server to confirm anything, but rather just send a request — if server accepts request and starts movement, it'll send back movement update, thus confirming you request emergently.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Why not have your server respond to all move requests with the new location of the client's player?

Example:

Client A requests to move its player from (15, 15) to (15, 16). Both the current position and destination are included in the request.

The server recieves the request and determines where the player will be after attempting to move from position to destination, and sends the resulting newPosition back to the client. In this case, the server determines that the request cannot be authorized because there is currently a unit occupying space (15, 16), and thus newPosition is (15, 15) since the player was not able to move.

The client recieves the response and moves its player to newPos. In this case, the client moves the player back to (15, 15).

It might create a bit of a rubber-banding effect, but you might be able to mask it by accompanying it with a visible/audible collision effect if the client response includes a "denied" tag, or something like that.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ This seems like interpolation with extra steps. \$\endgroup\$ – Shadows In Rain Jun 11 at 10:00
  • \$\begingroup\$ Well, there's no way to know what the server's response will be before you send the request, so if you want to use predictive movement, you're going to have to be able to undo incorrect predictions at some point in order to keep the client in sync with the server. My solution allows you to do that seamlessly and flexibly. \$\endgroup\$ – Agent Tatsu Jun 11 at 17:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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