PlayerIO

The fastest way to build online games without breaking a sweat.

Building Flash Multiplayer Games

This tutorial is also available in a pure flash version..

Table of contents
1 - Introduction 8 - Synchronization
2 - Game Basics 9 - Interpolation
3 - Turn Based Games 10 - Latency
4 - Network Architectures 11 - Tips & Tricks
5 - Security 12 - Game: Turn Based
6 - Example Game 13 - Game: Realtime uninterpolated
7 - Real Time Games 14 - Game: Realtime interpolated

Tips and tricks

Cubic splines

Earlier, we talked about interpolation and we presented a really easy linear method of performing interpolation.

But this is not an optimal solution to our problem. It is more then likely that our character did not in fact follow this linear path and it can make the game look awkward.

For example, if our character is heading to the right and we receive a state update that places him lower, we will end up with a path that looks like this:

Players will easily notice this as a problem due to latency. Players don't like problems due to latency! But what do we do? We've got a player in an incorrect position and have to move him there discreetly. How are we to do it?

The best case scenario is where we could give a more natural motion, like this:

This motion is smooth and believable. This is especially important in games that use velocity such as racing or a tanks game.

So, how do we go about implementing this rounded motion? Cubic splines of course! If you have had any decent education in mathematics, you will know that linear means it can be represented with an equation with a variable risen to the first power. ie. 5*x or 7*t

A cubic function on the other hand has at least one term risen to the power of three ie. (5*x^3 + 2*x^2 - 1) or (x^3 + 1) and it looks like this:

We can see that this fits with what we wish to use it for. A smooth function that accounts for velocities.

The only question is how to implement it. It is fairly straightforward in it's implementation even though the theory behind it involves slightly complex math. We will not touch on this theory as it is not necessary in order for us to use cubic splines.

First, we need 4 pieces of information, the object's position at the start, it's position and the end, it's velocity at the start and it's velocity at the end.

Now, using these numbers we must generate two more co-ordinates. The positioning of these co-ordinates will determine the curviness of your interpolation. Farther away co-ordinates will mean that the character will curve more away from the linear path.

We compute two more points. First is (our start point + velocity * curviness coefficient) and the second is (our end point - velocity * curviness coefficient) where the curviness coefficient is just an arbitrary number we multiply the velocity by in order to control how far away these points lie. Making this number 0 means that you will get no curve (a straight line). Making it higher will give more curve.

Now that we have our 4 points, we just plug it into the formula.

x = t^3 * (x4 - 3*x3 + 3*x2 - x1) + t^2 * (3*x3 - 6*x2 + 3*x1) + t * (3*x2 - 3*x1) + x1

y = t^3 * (y4 - 3*y3 + 3*y2 - y1) + t^2 * (3*y3 - 6*y2 + 3*y1) + t * (3*y2 - 3*y1) + y1

where t is time (between 0 and 1)
(x1,y1) is our first point
(x2,y2) is the start point + velocity * coefficient
(x3,y3) is the end point - velocity * coefficient
(x4,y4) is the end point

Note that this equation works only between t=0 and t=1 As such, start t at 0 and increment it by (1/number of frames to complete interpolation) each frame.

Once you have it working, play with your coefficient until you have something that looks good!

Semi real-time optimizations

Often you will want to create a game that is fundamentally not real-time but that has a real-time component to it. Good examples of this are pool and launching games such as gunbound or territory war. Each player's turn is discreet (separated, only one player is moving at a time) and as such only one person is broadcasting information at any one time.

This makes our lives very much easier.

Our first instinct is to treat this like a normal real-time game and send all our information up-to-the second with a high tick rate for our state updates, use interpolation to smooth it all out and even perhaps throw some event messages in there, just to keep everything on track!

But why?

Does the other player need to know what has happened at the very moment that it happens? No. It might be sort of nice in a way, but your opponent has probably been waiting a little while for you to make your move, a couple seconds is nothing really to him.

So, we don't have to send information immediately, how does this really help us in any way, shape or form?

Compact data

A vector consists of a direction and a magnitude. It can be thought of as an arrow

It is very well suited to being sent over a network due to it's compact size (two numbers) and it can be used to encode large amounts of data. For example, here is a pool shot encoded entirely with vectors.

The previous example had 5 vectors in it thus you only need to send those 5 vectors (plus give each a timestamp and velocity info, because pool balls decelerate) to express what could be as much as a few seconds of real-time movement. To show this in the classic way, we would need to use something like 30 state updates! That's ugly! Furthermore, this method tells us exactly what happened, instead of us approximating it from a datastream.

In other words, sending compressed data that describes a turn fully AFTER it has happened is very powerful. We relieve ourselves of bandwidth strain and get a more accurate result all in one fell swoop!

Normally, this information can be shown using some type of vector (or a chain of vectors.) Below, we see the tank move, then shoot. However, our projectile path isn't straight...

Often, we will have objects that have forces applied to them such as gravity. As long as the force applied is constant, we can still model this object's movement easily. You may be tempted to just give a launching angle and speed, but this can get you into trouble. As the message is transmitted across the network, rounding errors and the like can pop up. This means we cannot trust simulation of the flight alone in order to give us a proper reconstruction.

What we CAN do, however is send along the end point along with the launch velocity and angle then ease out any errors discreetly, making the projectile land where it is supposed to in the end.

Even better, we could model this type of movement with a quadratic formula or a higher order function if it is required (much like what we did with our cubic spline)

In this case we would send the co-efficients for the equation A*t^2 + B*t + C and thus easily reconstruct the entire flight path. If the object's movement is complex, this sort of re-construction becomes preferable. For example, the below path could easily and accurately be reconstructed using three quadratic equations and co-responding timestamps.

In this case we would send the co-efficients for the equation A*t^2 + B*t + C and thus easily reconstruct the entire flight path. If the object's movement is complex, this sort of re-construction becomes preferable. For example, the below path could easily and accurately be reconstructed using three quadratic equations and co-responding timestamps.

Streamed delayed messaging

But what if you want players to see what is occurring before everything is over? For example, if a player's turn has a minute of input then the next payer will have to wait a minute while player 1 acts out his turn then another minute as he sees it played out on his screen. The time is takes for turns to execute is doubled! That is excessive!

So, we want to stream out player movements to reduce this delay. All that is required is to record player actions for a reasonable time period (say, 5 seconds) then send that over. Record for another 5 seconds, etc. We gain similar gains in terms of bandwidth and accuracy but the other player has information that is only 5 seconds old!

Real-time application

If we can have a low delay between when an event occurs and when we see it, we can start applying this sort of philosophy to moderately real-time games such as an avatar chat or an MMORPG. The key element is: do players need to see what each other are doing at that very moment to play properly or can they wait a moment?

For example, if players are running around in circles saying "Ha-ha, I'm running around in circles!" would it be a detriment for this information to come in a little bit later then it actually happened? In such applications, players are fine with receiving late information because if does not effect their experience at all. They can still run around, laugh and talk plus they will still see the same events and will likely not be aware of any delay (and with no perceived lag to boot! something many avatar chats simply cannot provide.).

We can do even better, however, by knowing the future before it happens!

Ever noticed how popular click-to-move is in MMOs or other assorted large scale games? Why is that exactly?

It's because this method is cheap and inexpensive! When you click a point to move there, you send a single co-ordinate out to the server. That's it. Your movement is done. There are no synchronization issues here. The server sends out that point, your character moves, stops at that point and everything is dandy! We have a fully fleshed out movement/vector before the move is even made!

If we package all these moves together in one large state update before sending it out to our players, we can get great efficiency and an engine that scales well!

Oh, but latency

But you didn't think latency would actually give us a lucky break, did you?

For all the vector-based or pre-known movement discussed earlier, there is a major problem. Recall that latency varies. If we have a fluctuation in latency then there could be a space between our messages. A small period of time in which we have no information and are thus forced to stop. For example, packet 1 takes 100ms to travel but packet 2 takes 200ms.

This throws a wrench in our otherwise perfect plans. We will have players stuttering all over the place if we don't do something to rectify the situation and smooth everything out.

Happily, the solution to this problem is simple: Don't act on the information the moment you receive it. If we were to try and maintain a buffer between when we obtain an update and when we act on it, we could easily handle small fluctuations. For example, if a message was delayed by 50ms from the previous one but we had acted on the first one 100ms after we had gotten it, we will have the previous update still playing when the next one arrives. By doing this, we can have seamless transitions between updates.

Of course, by coming 50ms later, that packet has bitten into our buffer time. We are then only acting on information from 50ms ago.

Fortunately, under normal circumstances, the latency cannot grow forever but rather fluctuates around an average point. On most occasions, this means that the latency will go back down and we will get our next message earlier then expected.

Otherwise, we would have the same problem again. Our buffer is gone and we are forced to act on information immediately. We have two options: stay the course and hope latency goes back down or slow down the current perceived movement and try to rebuild our buffer slowly and discreetly (easy if each update is large compared to our buffer. to rebuild a 100ms buffer within 5 seconds we only have to decrease the player's movements to 98% which is not noticeable by a player.)

This fix has roots in true real-time environments too.

Delaying action in real-time

Latency fluctuations hurt us badly in real-time games as well. It is very hard to achieve good sync when the message you are supposed to be syncing to is late. You can try and predict movement for the small recess of time that you are waiting (a fraction of the ping time), but we have seen how badly predictions can turn out and we would like to reduce prediction to a minimum if possible.

Thus, it is actually common practice to delay movement by a whole state update, even in modern FPS. By delaying action for a whole update, you are acting between two points that you already know. All that is required is a smooth interpolation between the two points. (unless the second point is late, then you must extrapolate using the event updates (this will still give exact movement because you know the event update times))

Is ____ fix right for my game?

Note, however, that you are essentially adding artificial latency into your game. The game will be reacting a fraction of a second after it receives information. In compensation, however, get rid of (or, at least seriously dampen) latency fluctuation issues.

For all of the fixes throughout the last few chapters I have tried to make it clear what the pros and cons of each are. Which ones you implement (if any at all!) are completely game dependant. If immediate movement is more important then exact, unbroken movement then you will want to implement different things then, say, a game of pool.

Each game has it's own network personality. In fact, barely any two games have exactly the same personality when you look at how the network must function to run them. Think about your game and it's fundamental needs then work towards them (or change them to be easier to implement!)

Scaling multiplayer games

Indie developers have often been know to be bold, innovative and explore new areas that have never been tread before. As such, you might be tempted to be like the bold, innovative creators of the ridiculously large new game MAG. If you have not heard of this game, it features 256 players online on the same map in a giant FPS battle. Unless you are a certified genius I would not try something like this in flash (or any other platform for that matter).

But why not? It is possible to have 256 players in multiple different rooms. Why not put them all into the same room? You'd have the same load on the network, right?

Wrong! Multiplayer games scale according to O(n^2). Those of you who know what that means will see the problem immediately. For those who do not, however...

For this example, let us say that there are n players connected.

You must share your information with every other player connected. Thus, after you send your information to the server it must be sent out to n different people. This requires n different messages.

Of course, each player has to be sharing his information thus he sends his info to the server which in turn sends it to all n players. This is a problem. because the amount of information shared can be modeled by n*n which is n^2

As n, the number of players, grows large the strain on our network gets very large and becomes unfeasible quickly.

If you were to apply this logic to MAG with 256 simultaneous players then you would wee a result of 65536 pieces of information shared. Is this a case of innovating oneself into a deep hole of darkness and no return? No it is not! The creators of this game are master magicians first class!

Having each client send their data to each other client is very brute-force and results in a very ugly net topology. We can do better then this.

Culling

Why send numerous state updates to players who can't even see you and don't care exactly where you are? At any one time, a player should have a fraction of the entire playerbase on his screen. Culling is a very basic and simple way of reducing the load of a game with many players in it by simply not acting on or sending unnecessary data.

Imagine, for argument's sake, that we were crazy enough to try and make a 256 player game. This will give us good insight as to how we can make our game scalable, even if 256 is well out of our reach.

First, we must design the game in such a way that we can be relatively sure that all 256 players aren't going to be able to see each other under normal circumstances. If that were to happen then our first line of defense, culling, would not work. We'd like the player to see perhaps an average of 15 other people.

Every update, the server would check your x and y co-ordinates to figure out which players can see you Then it only sends your position to the 15 people who can see you. Note that you should add a buffer space (at least 200 px) when deciding if another person sees you or not. If the person is JUST off-screen, they might get on-screen and cause you surprise when they pop out of nowhere next state update. Or, part of them might stick out onto your screen, etc.

Now, our game grows according to 15*n which, with all 256 players, would spit us out a base number of 3840. This is 17 times better then before culling! Already we are much better off then we were before.

But can we shave even more off this number?

Of those 15 people we can see, do we need to give the full intensive state and input synchronization combo treatment? (Note that these techniques work for MMORPGs as well. And in this type of game, the kinds of numbers that we are talking about are quite common!)

Obviously we are not going to interact with all 15 of these people all at once! That is more input then a single person can handle! Recall, however, that if you are not interacting with a person, we do not particularly care what they are doing at this very second. We can afford to send less information and/or delayed information and still get good results.

Prioritizing updates

Does the player really care about what his teammate off on the edge of his screen is doing at this very moment? Is it important enough that he must get the information NOW instead of getting it 300ms later, a time lag we would only notice if we could we what was on his screen.

Similarly, in an MMO, the player REALLY doesn't care about the people walking around town near him (towns tend to be fairly crowded) unless, of course, those people are in his party or guild or he wants to trade etc..

We should be conservative, however. Lagged updates on something that the player needs to react to can seriously hamper the player's experience. Proper balancing, however, can yield great results! If you have cut out all that huge bandwidth by eliminating what the player doesn't care about, we can send the player more about what they do care about such as party members or enemies who are shooting at them.

Under a very bad network load where the entire game is going to hell and ping spikes up to 1000ms, these fundamentals become even more important. We know that the player is going to experience fragmented gameplay and laggy conditions, but the game can be salvaged and still playable until the situation abates by focusing our energies on the important parts of the game.

In an MMO, if the network gets clogged, the last thing you should do is stop accepting player input. It is preferable to cut updates of other player's positions (or slow them) and let the player still walk around and attack monsters (or run away until the lag subsides). Similarly, in an FPS you would want to try and keep updating the position of the enemies that are a danger to them so they can still aim and fight.

Getting back to our 256 player FPS example, we can reduce the load from at least half the people we see because they are team-mates. We don't need to know what they are doing unless we are intimately interacting with them (such as a co-ordinated push). Depending on how much your game has you interacting with friendly players, you can get away with quite a bit of slack in the friendly player sync. As an extra bonus, you will see more friendly entities in a game then unfriendly ones. Any time you see more unfriendlies then friendlies, you tend to be dead.

So, we can halve the number of state updates we receive about our team mates (the ones we don't care about) and then set them up with an action delay of up to 300ms to ensure they give smooth movement. This will give us un-erring movement (300 ms is more then a single state update) and all the player will see in his peripherals is smooth gameplay.

It is safe to say this could reduce our network load by another half. Changing our base approximate to 8*n and giving us 2048. This is just as efficient as a non-optimized 45 player game!

Of course, we can't really handle a 45 player fully real-time game with the given technology and audience limitations. Even a 10 player fully real-time game could be taxing before optimization. With a system that is less demanding on resources, however, we can get very good numbers indeed. In the hundreds at least.

The number of players you can support and the amount of traffic needed to support each player is inversely related. If you only had to send one relatively small update to each player every 10 seconds, you could potentially reach even up to 1000 players! (at this point, it becomes harder to get that many people in a game at once then to code it!) Also, if you were to connect that many people, you would need to stagger messages from the server. Instead of sending all 1000 players their info at once, we would like to trickle it out over those 10 seconds.

Designing a good multiplayer game

It is easily evident that a game as massive as 1000 players could be logistically unsound. But, game like this exist! What makes a 1000 player FPS (assuming it could exist from a technical point of view) logistically unsound while an MMO or a browser game can have thousands and still hunger for more?

Furthermore, what in a multiplayer game makes players want to come back for more? What makes the game ultimately successful and what will make players willing to purchase items inside your games? (for many of you, the last consideration is the most important of all!)

Many of these questions have never been fully answered by anyone and any satisfactory response would envelop up to 100 pages of writing. We can take a stab at most of them, however...

Asynchronous games

Asynchronous means exactly what it appears to. Something that is not synchronous. It is important to note that at any one time, there are more people playing an asynchronous games then it's loyal counterpart, the synchronous game.

Of course, you're wondering exactly what this terminology means as applied to games. It means that the game world is not necessarily tied to the players but instead exists as it's own free entity. Before the player joins, the games exists and after they leave it still exists, waiting for them to join again. The best example of this is an MMO or a browser game such as mafia wars. The game continues after the user logs out.

What is the irresistible allure of such a game? There are many and it should be easy to see that this type of game fits the casual market quite nicely.

For one, the game fits the player, instead of the player having to fit the game. They can play for 15 minutes per day, or 5 hours. The game is impartial to this. Note that this is not as much a positive attribute for asynchronous games as it is a negative attribute for games that sync to the players such as a board game. In this type of game, the player must put aside a distinct chunk of time just to play one game. Also, you generally have to wait for other players.

Making our games have a distinct start and end plus the need to wait for players is not a feature our players want. Instead, it is a logistical nightmare and cannot scale to any large degree.

Imagine trying to gather 1000 users all at once to start a massive synchronous game. It's just not going to happen! If you somehow manage to gather 500 users, half the amount required, many of them will simply leave, seeing that it will take a while to fill the game to capacity. Being sheeple, the rest will generally follow the first deserters.

We don't even have to reach to such heights in order to see that this simply doesn't scale. Even trying to wait for 10 people is an uphill battle. Hell, many a player has grown tired waiting for a single partner.

We should design our game with sudden entrances and sudden dropouts built in. Not as "an available feature", but in a way that the player is almost encouraged to do so! Why should a player who starts a new game in a fighting or shooting game be forced to wait around when he has a perfectly good engine laying beside him? Let him shoot practice dummies for minimal exp until a second player arrives! Afterwards, when a game is in full swing, ensure that new players joining up are not disadvantaged and players who leave will not create a void in the game.

You do not even need to built a asynchronous game to reap the benefits that such a game usually gives. As long at you design your game with the basic benefits in mind, you will be fine.

Take Diablo as a prime example of this. To play the game you needed to join or create an independent instance. This is fundamentally synchronous behavior as the game depends on player existence. But, you could join up the game at any time, leave with no regrets, play for any length of time.... The player still gets the benefits!

When working with playerIO, this is the setup that you should use. As part of the lobby system, each game instance is attached to the players within it. The players must create the rooms and when they all leave, the rooms are destroyed. But, by letting players join or leave at will, we can easily make a game that fits the market.

The point of multiplayer games

Finally, remember that the most important aspect of a game is the players and how they interact with each other. The most successful games do not try and become the end-all of entertainment but instead try and become the lubrication between player interactions.

If you are designing a game that is highly competitive, make sure you focus on bringing players together and facilitating competitive structure (allow clans, etc. that group together to defeat each other). Players will tend to be much better at organizing themselves then you are, with the proper direction and understructure. You have a game forum, use it! After being shown how and being given the tools to do so, players can organize community tournaments.

If your game relies on socialization instead, innovate on the social side of things instead of making more ways for players to whack monsters. Add emotes, guilds, ensure that they can talk with each other whenever and however they want. Many players will play your game just to interact through these means. (and then come back after they've made friends)

Keep a cool head and keep proper perspective on what you are actually trying to accomplish with your game and everything will turn out alright.



Table of contents
1 - Introduction 8 - Synchronization
2 - Game Basics 9 - Interpolation
3 - Turn Based Games 10 - Latency
4 - Network Architectures 11 - Tips & Tricks
5 - Security 12 - Game: Turn Based
6 - Example Game 13 - Game: Realtime uninterpolated
7 - Real Time Games 14 - Game: Realtime interpolated


About the author

Ryan Brady is a Canadian developer who is currently going to the university of Waterloo. When he isn't fooling around with friends or dealing with an ungodly amount of course work, he likes to design and build games.

Two of the things Ryan likes most above all else are sarcasm and irony. Thus, he likes other people when they have a sense of humor and don't take offence at playful stabs and teasing. Otherwise, people tend to think Ryan hates them and/or the entire universe.

Subscribing to the "Work hard, Play hard" mindset, Ryan is always on the move. There are not enough hours in the day to do everything he wants to do (which is quite a bit). As a habit, Ryan designs more things then he has time to make. Alphas and proofs of concepts are his bread and butter though he always wishes he could make them into full games.

Every so often, you will see Ryan with a full beard on his chin. This commonly refereed to as Schrodinger's beard as you never know if Ryan will have it when you see him next. He re-grows it in under a week.

Every 4 months, Ryan has a co-op term so he moves around quite a bit. He might be living in Canada one month then be living in San Fran the next. You will never know when Ryan will be at large in your area next (until it is too late).