🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Game synchronisation in peer-to-peer online multiplayer game

Started by
3 comments, last by hplus0603 7 years, 3 months ago

I am developing an online real-time multiplayer game using Google Play Game Service and Cocos2D-X. The game has two players where each player control their own ball.

The each player sends their own ball’s velocity and position to the other connected device. In my game, all the physics calculations are done locally on each devices i.e. ball velocities after physical calculations are calculated locally on each devices.

Issue:?

When fast moving ball collides wth the opponent’s ball, there is no change in the movement velocity of the opponent’s ball. (According to real world physics, the fast moving ball should be able to push the opponent’s slowly moving ball.)

Reason:
During my code analysis, I understood that the velocity calculated by the local physics engine are over written by the data received from the opponent’s device.

For e.g.
puo8v.png

Solution I tried:
To fix the problem, whenever the collision between balls occurs I am creating one of the device as server and other device as client. All the physics calculations occurs on the server device and data is send to the client device.

I have following questions:

  1. Is the solution tried by me is optimal solution to fix the issue?
  2. What other approaches can be tried to fix such type of issue??

I would appreciate any suggestions/thoughts on this topic. Thank you.

Advertisement

You're going to run into a much harder problem, which is that by the time "your" ball position/velocity data packet makes it to the "other side," anywhere between 20 and 500 milliseconds will have elapsed, because of the unavoidable network transmission delays. Unless the balls are large and slow, you will not generally see the collisions the same (or at all) on the other device.

If you elect one device as "server" and call it "authoritative," then you will have unfairness between the simulations, where the server player has no latency, but the remote player suddenly has a full round-trip time of latency! For most action games, this is a pretty big handicap.

Dealing with latency, and the unavoidable knowledge gap between the two ends of the simulation, is why networked game design is hard. You need to come up with good ways of solving the latency problem at the game design level. Maybe add some delay between commands and effects, so that the other end knows about your command in time? Maybe let each player react to what they see, and send some message about the reaction they saw, but allow the play to look different on the different devices?
Maybe display the remote entities "ahead of time" using extrapolation, in an attempt to minimize the perceived discrepancy in position/orientation?
Or, most commonly, carefully apply all of those solutions in some kind of mixture, to make the kind of gameplay that makes the most sense for your game.

And, it turns out, some games just cannot be well implemented over a network with a lot of latency. For example, tennis would be a lot more robust to latency correction than something faster, like ping pong/table tennis.

enum Bool { True, False, FileNotFound };

Thank you for the reply hplus0603. Your suggestions regarding flows in my current design are helpful.

Currently, the code is using extrapolation. The ball positions are updated using the physics body in the update loop. Hence, the ball position is updated on the remote device even if the remote device is not receiving data packets for the ball.

  1. How can I ensure that the collision between balls happens at the same instant of time on both the devices so that local physics engine work properly?
  2. or else how can I ensure same physical collision between balls (on both the devices) given I am sending the ball velocity to the other device?

How can I ensure that the collision between balls happens at the same instant of time on both the devices

You can't. To do so, you'd have to guarantee that both devices were perfectly synchronised in time, which is theoretically impossible to do perfectly (thanks to relativity) and practically nearly impossible for other reasons (network jitter, different device update rates). Systems like Network Time Protocol are specifically designed to synchronise computers across the internet to within "tens of milliseconds" across the internet - and that is not good enough for a fast-paced physics simulation.

You could probably do better and get within single digit milliseconds of each other, but not only is that still not good enough, but now the latency is a big problem - your balls might be in almost the same position on both devices but any player input cannot possibly be fully synchronised because it takes time to travel across the network.

I think the closest thing to a solution here is to have a 3rd process act as an authoritative server. Unfortunately Google Play doesn't offer this (the last time I checked). But it would allow you to have a single place where all physics is performed and where the results are broadcast out to players. Unfortunately this introduces extra latency between player input and the game's response to that input, but that can sometimes be mitigated or covered up.

How can I ensure that the collision between balls happens at the same instant of time on both the devices so that local physics engine work properly?


Kylotan's first answer is my first answer: "you can't."

But it's not quite that easy. You can, in fact, run consistent multi-player physical simulation across a medium with latency. You have to accept the trade-off of command latency instead.
If the time it takes to actually see your command take effect on your local screen, is the same time it takes for that command to reach all the other players, then they can all apply the same command at the same time in their individual simulations, and the simulations will be consistent.
Using "ticks" for time (note: FIX YOUR TIMESTEP!), when you make any kind of command (change throttle, turn, jump, etc) then you have to "queue" that command for some future simulation tick, and send it to all the other players to apply to that simulation tick as well.
Each simulation will then wait for the other players' input data for a specific simulation tick before they actually execute that tick's simulation.
The number of ticks into the future that you need to queue your commands equals the duration it takes to get the oldest command in a network packet to all the other players, so one-trip transmission time, plus one network packet interval, plus one simulation frame.
The game genre where this works the best is real-time-strategy games, where the "yes, sir!" acknowledgement animation for each command elegantly hides the transmission latency, but it can be used for other game types, too.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement