← All posts

Getting the Timing Right in Online Games

Playing "together" with someone online is a lot more complicated than it looks. On the surface, it feels like all you have to do is connect both players to the internet and exchange data. In reality, it is not that simple at all. There are a lot of things that make this hard, but the biggest one is timing.

People often assume that when you send data, it reaches the other person immediately. It feels almost instant, so that assumption is understandable. But in reality, it is not instant - it is only close to instant.

Data still has to travel through physical space. And there is a hard limit on how fast that can happen. Nothing can go faster than light, and the optical fiber and networking equipment we actually use are slower than that. On top of that, the route is not a straight line.

If you look at the map, Seoul and New York are about 11,000 km apart. At that distance, round-trip delay becomes something people can actually feel. In the real world, once you add slower propagation inside fiber, routing detours, and all the network equipment in between, going over 200 ms is not unusual at all. For someone who types quickly, that is enough time to type about two characters.

So what about Seoul to Seoul? Is that basically free? It is definitely much better, but it is still not "close to zero". On a normal internet path, data still moves through ISP infrastructure and multiple devices, so seeing something like 30 to 50 ms is pretty common. On the other hand, if you keep servers close together inside the same AWS region, that can drop into single-digit milliseconds. That difference matters a lot. In the end, when you make an online game, you have to build it around the fact that what you are seeing from the other player is not their state "right now" - it is their state from a few dozen milliseconds ago.

The approach I chose was to use a shared time reference. I use the game start time as a common baseline, and each client records the time when its own events happen. If I select something, my client records when it happened. The other player's client does the same on their side. Then, when I receive the other player's data, I do not just process it in the exact order it arrived. I insert that event between my own events based on when it actually happened.

That makes the on-screen sync feel much more natural, even with network delay. Of course, it is not perfect. Sometimes an event I saw first was actually later than the other player's event, but their event arrived late because of transmission delay.

In my game, though, that was not a critical problem. It is not the kind of game where extremely precise timing is everything, and those cases do not happen that often. So instead of making the whole system heavier, I chose to handle a few edge cases only in the presentation layer. Even that was enough to give players the feeling that they were really "playing together" - even though, in reality, they were looking at each other from a few dozen milliseconds in the past.

All posts