Before Instagram was a billion dollar company, Mike Krieger posted a presentation called Secrets to Lightning Fast Mobile Design about how his team made the Instagram photo-sharing application feel so responsive, which is one of the key reasons their company has garnered so many users so quickly. This slide caught my attention because the same trick is a cornerstone of good online game design:
To ensure a great online game-play experience, your job as a game designer is to minimize the perceived latency between initiating an action and having that action actually take effect in-game, even though there may be 300-400 hundred milliseconds of actual latency between the game client and game server. Actually, I might be dating myself a bit — early Real-Time Strategy (RTS) games had to expect such huge latency because most players were using modems. Internet latency is much lower now but user expectations are higher, so every trick we can use to hide that latency is still useful.
First, it’s important to recognize why latency is so high in RTS games. Games like Warcraft, Starcraft, and Age of Empires are built using a “lockstep model”. All of the computers running a game simulation perform player actions “at the same time”. Well, not at exactly the same time, but during the same game “turn”.
It works like this: when you tell your Ogre Mage to attack my Peasant, your computer sends a network message to my computer. And then your computer ignores the attack action for a while. What?!? Yeah, your computer can’t act on that action yet because, if it did, your computer and my computer would be “out of sync”. Your computer has to wait until it receives my message for that game turn, and then both of our messages can be processed at once. Here’s a diagram that shows what’s going on:
If you’re interested in implementation details, Mark Terrano wrote 1500 Archers on a 28.8: Network Programming in Age of Empires and Beyond. The Warcraft and Starcraft RTS games used the basic same network model a couple of years prior, but Mark gets big props for writing the first article. And here I am just starting to blog 15+ years later!
So anyway, what this means is that, even though your game engine knows your Ogre Mage is going to attack, it can’t do anything to modify the state of the game world or the simulation will be de-synchronized.
Which means that you’re not getting any feedback that you’re about to kick my ass. No fun!
So here’s the solution: provide instantaneous visual and auditory feedback, without making changes to the game simulation.
Remember all those funny voices in Warcraft: “Yes, milord”; “At once, sire”, “Daboo”, “Zug Zug”? While quite entertaining in and of themselves, their fundamental purpose is to immediately reassure players by confirming that their orders are being obeyed.
In addition to playing a sound effect ‘Craft games also played an animation effect on the map-screen which, while it had no effect on the game-play, showed the target of the action.
So there you go, another tool to add to your game-designer toolbox. Improving online game responsiveness is not just about writing better networking code to minimize Internet latency, it’s about finding ways to minimize perceived latency by providing instantaneous feedback to user requests.
I have an amusing counterpoint regarding: “provide instantaneous visual and auditory feedback.”
Many years ago i was working on a client-server program that could be configured to use TCP, UDP, or even ICMP for a command channel. From a user experience/interface point of view, I had the opposite problem. The command to connect using UDP often succeeded too quickly. Especially when compared to the default UDP option. It was a heavyweight client. And there was a nice button that stayed depressed and turned green when the connection was successful. Having the status immediately change was seen as occurring unbelievably quick. Such a significant user action as “reach out and establish connection with a server” needed to include some anticipation.
Solution: Sleep(600);
Gabe – your Sleep() solution is user-interface affordance in action!
Thanks for this explanation. I’ve often wondered about this very topic. So ‘lockstep’ handling of events eliminates the need for any kind of conflict resolution between commands issued by players.
The use of sound and animations to confirm that an action has been received by the game engine before processing that action is quite clever. However I think it also explains why sometimes (rarely) during a game of Starcraft BW a unit like a Queen would be seen by a player to cast a spell, or at least begin casting it, but when viewing the replay the Queen would die without casting the spell.
From playing Starcraft WOL on a sometimes laggy mobile connection I notice that during the wait period additional commands can be issued, I suppose they must be buffered and then processed in lockstep.
You’re right — the lockstep model ensures that no server-moderated conflict resolution is required.
And in regards to command-queuing you could issue multiple commands per network frame (every 1/4 second), which is what enables players to sustain 300 APM (Actions Per Minute). Those APM numbers still boggle my mind!