In your specific case, what you’re talking about is physics, keeping it in sync over a network, and afaik there are three ways to deal with it (this is taken from some notes on my computer, apologies if I’ve missed anything). Say you have two players, and the two clients are connected:
You can run the simulation on one side at a time:
- You keep the simulation (positions, velocity etc) on the client only, and send player inputs only between the two players. So player one sends command to turn left, that’s reflected in the other player’s client. This is called deterministic lockstep, and what it depends upon is the physics simulation being deterministic, ie the game starts on either client and, given the same set of inputs, the engine behaves in exactly the same way (no tiny differences, exactly the same, because if there are even tiny differences the two clients will steadily diverge from each other). This means you don’t need to store data anywhere, it’s all on the clients. But floating point is a massive issue here. And latency is also an issue, because player2 can’t do anything until player1 input comes in and vice versa.
- You send a snapshot of the game state [the important bits, like where the cars are etc, not the entire game] of player1’s client to player2’s client and interpolate it with their game state, and vice versa. This is called, surprisingly, snapshot interpolation. And it means big packets of data (whereas deterministic lockstep is tiny packets of data). This is very effective, but you need strategies to make the data as small as possible, which is where the complexity comes in (otherwise it is super laggy). It has the advantage that if an update fails for whatever reason, then the next one can be used or the next one and so on; the game state should just be smoothly interpolated between previous and current. It has the disadvantage that it doesn’t know about the physics, so if there is a gap between updates, players will [more often than with other approaches afaik] see weird behaviour when there are gaps in the data, like stuff going through walls as the cars update from one position to another.
You can run the simulation on both sides at the same time:
- Both clients send each other their state and inputs, and the game synchronises the state on each client based on that (state synchronisation). This has the massive advantage of things still running for each of the players between updates. Less data has to be sent less often than in state interpolation, and the physics does not have to deterministic like in deterministic lockstep. But what you lose is exactness: everything becomes an approximation.
So those are the three approaches, and they don’t need a server. But in practice they kinda do, because there generally needs to be some authority about what is correct behaviour in the game; latency is the killer, and just having two clients communicating directly is likely to result in a bad game experience (there are situations where it’s not an issue, eg RTS games, especially where it is one player’s turn, then another player, and it’s fine to just back and forth between clients even on bad connections, as it has no real bad effects on gameplay).
So you have a server that knows the state of the game, and one of the three approaches described is used (or some combination thereof), with the server as kinda the referee in the middle. There are now an extra two hops for the data to make between the two players’ clients, but that can be masked on the client side using various tricks.
The storing data – the game is effectively being played by the server. A database on its own is not really any use, although there are some available that are optimised to be very fast, for game usage, but they would be supporting the application code running in the server.