When making a multiplayer game, one of the most important issues to cover is how your networking communications will be addressed by your game design. The game characters are constantly moving and you should be able to position them and transmit their location accurately to all the players.
But, what type of information should you send to communicate between players if you’re making a real time multiplayer game? You’ve got several options to start off:
- The position of every character, the exact position at any given moment
- Start and end position of every character, and have the client interpolate the position
- The user inputs that makes a character interact with the game, aka commands
Let’s break down the characteristics of these options and the problems they pose.
#1 The position of every character
This is the most simple approach when trying to communicate with multiple players. The fundamental issue with this approach are the amount of messages that need to be broadcasted, even for simple games.
Let’s say that you want to make a 3D game that allows three players to play simultaneously and that you want it to run on 30 frames per second. That makes 90 msg/sec. If every character position has 4 variables: x,y,z for position, and α for rotation, you’ll have to process 360 variables/sec.
Let’s see how much time you have to process every frame of your game.
1.000 milliseconds / 30 fps = 33,33 ms/frame
In those 33ms not only should you compute the position of the players, but also cram in graphics generation, IA and networking communications. This isn’t automatically obtained, you’ll need code that’s optimized to guarantee that it works perfectly on all devices.
Bear in mind that server has to manage all messages from all three players, that makes 270 mps total, that’s three times 90 mps.
But, what if one of the three players has a better device that runs at 40fps? It’d mean this device receives additional messages the 30fps devices aren’t receiving, and these extra messages could originate a collapse.
Now imagine that besides all the player positions you have to control the position of NPCs (non-player character) because your game is multiplayer and also has an environment that spawns characters. This would further complicate communications because it adds more positions.
#2 Start and end position of every character
If you feel that sending the characters’ position at every single frame is too costly for the game’s performance, the next approach could be one that doesn’t send messages at every frame but one that does it every certain amount of frames. Setting it this way will require the client to interpolate the movement path of the characters based on an initial position and a final position we’ve sent to the server.
This, of course can lead to the issue of “ghost strikes”. To illustrate the issue, let’s return to the example where your game is played on different hardware with different simulation speeds.
Mary plays in a state-of-the-art device, sees the Enemy in a certain position (x,y,z,α) and hits him. Good!
Now Mark, who is playing in an older device with lower specs, sees the Enemy in a different position (x-1,y-1,z-1,α-β) and sees Mark failing to hit the Enemy. In Mary’s simulation, the Enemy is still at full health, resulting in a different representation of the game state.
So, we know that just with the positions of the characters we don’t have enough information to be consistent across devices with different specs. One way around this is sending messages of special events that happen on the game. For instance: a hit, a death, a spawn, and so on. This adds more messages the server has to manage though, so we’ll have to calculate whether all this information can be manageable by the different clients.
#3 The user inputs that makes a character interact with the game
This is an interesting approach because it allows you to send much fewer messages than in the previous examples if done right. In this case, we don’t actually send the position of the characters, but the commands the users are doing to make their character interact with the game.
What are realtime server commands? When a user starts pressing “right” in the game pad is one command. When the same user finishes pressing “right”. User hits A button. Commands vary from game to game, but you get the idea.
What the users in the multiplayer game receive as messages are those commands, so their clients are the ones who have to make the game simulation according to that information.
Regardless of the type of information you send to communicate between players in a real time multiplayer game, you’ll always have the issue of different times of simulation caused by the spec disparity of the players’ devices. To even out device disparity it may be necessary to send at what moment (in milliseconds, frames, etc) the simulation should take place. In this case, a global synchronized clock is usually agreed upon among all players to be able to simulate the game correctly.
Final caveat on realtime server commands
It is important to realize that besides computing character positions there’s many more that has to be calculated: graphics, IA, and more. This fact makes planning our communications a priority, and figure out how much time we’ll have to calculate and process the messages according to the frame rate we want to achieve.
Soon, I’ll write about one common issue all multiplayer games face to design a truly real-time experience. What’s lag, how it originates, and four techniques to mitigate it.
That’s it! But before tuning out, check our solution to make realtime multiplayer games that are fast and reliable.