Multiplayer tutorial 1: concepts

60

Index

Features on these Courses

Stats

84,063 visits, 356,711 views

Tools

License

This tutorial is licensed under CC BY 4.0. Please refer to the license text if you wish to reuse, share or remix the content contained within this tutorial.

Published on 3 Mar, 2014. Last updated 12 Sep, 2023

How many players can join the same game?

The limit on how many players can join a game is likely to be the upload bandwidth on the host. The engine itself imposes no limit, but there is definite practical limit that will be encountered.

The problem is the host has to send a message with data for N players, to each of the N players. For example, if the host needs to send 16 bytes of data for each player, then each message will have a size around N * 16, and then that message will have to be sent N times. This creates an N-squared bandwidth requirement. For example:

10 players = 16 x 10 x 10 = 1600 bytes per update

20 players = 16 x 20 x 20 = 6400 bytes per update

30 players = 16 x 30 x 30 = 14400 bytes per update

...

100 players = 16 x 100 x 100 = 160000 bytes per update

Even though the player count increases linearly, the bandwidth requirement increases proportional to the square. This means even with a significantly more powerful server or less data needed per-player, it won't get you many extra players.

By default updates are sent 30 times a second, so the last example with 100 players would actually require an upload rate of about 5 megabytes/sec (or 40 megabit/sec). This is pretty high for a home connection, but not necessarily a dedicated server.

On top of that the host needs to be able to run the game for a large number of players as well, performing tasks like lag-compensated collision tests, which can be CPU-intensive. Then it may need to be rendering the game for the host if they are a participant as well. Generally the overall amount of work increases quickly with the number of players, and although it depends on the specific game and connection, it's rare to get close to 100 players in one game.

Controlling the update formats

It's possible to choose the exact data format of values tansmitted by the multiplayer engine. Used correctly this can significantly reduce the amount of bandwidth required without having any significant effect on gameplay precision. This helps make the game make more efficient use of the network, as well as likely raising the maximum number of players who can join.

If you are not familiar with bits, bytes and binary, then it has been covered extensively elsewhere. Consider starting with the following Wikipedia articles on binary numbers and byte. In short, all numbers in computing are stored in binary: each digit can only be a 0 or a 1. A byte is 8 bits, and can therefore store 2^8 (256) different values, or from 0 to 255. More bytes allows for a greater range of values to be stored. Floating-point types can also store fractional values, such as 0.3, and generally require at least four bytes.

The types you can use in Construct are:

High (double, 8 bytes): a double-precision floating-point number that can store numbers without affecting their precision. It has about 15-17 significant digits of precision. However it takes 8 bytes to store a single number, which can end up increasing bandwidth requirements significantly. In practice this is unlikely to be a necessary choice.

Normal (float, 4 bytes): a single-precision floating-point number that can store fractional numbers with about 6-9 significant digits of precision. This means some numbers will be rounded to fewer significant digits. However it is usually far more practical than a double, since it only takes half as many bytes and digits beyond the first 6 are usually unimportant (e.g. 0.333333 is close enough to 0.333333333333333 for practical purposes).

Low (int16, 2 bytes): a signed 16-bit integer that can only store whole numbers in the range -32768 to 32767.

Very low (uint8, 1 byte): an unsigned 8-bit integer that can only store whole numbers in the range 0 to 255.

To minimise bandwidth, it is important to choose the lowest precision possible that will not seriously affect gameplay. For example X and Y positions can often use low (int16) precision. As long as the layout is smaller than 32767x32767 (which is very large), and sub-pixel positions are not important to gameplay (since this will round off any fractional value), it is perfectly sufficient and uses four times less bandwidth than a double.

The low (int16) and very low (uint8) precisions are useful with player inputs for peers to send to the host. Using the setbit, getbit and togglebit expressions in Construct, it's possible to set individual bits in these numbers. If a game uses the four arrow keys to move and space bar to shoot, these are only five controls, and can be stored in 8 bits with a 0 indicating 'not being pressed' and a 1 indicating 'being pressed'. Then the host can look at each bit and simulate the appropriate controls. This can all be done with a single byte, or an int16 if you have more than eight controls, making very efficient use of bandwidth. Similarly the host can send to peers multiple on/off states in a single value.

  • 27 Comments

  • Order by
Want to leave a comment? Login or Register an account!