Designing a free to play game with microtransactions is a huge challenge. It is incredibly difficult to find the perfect balance between giving players a strong incentive to pay something while still making the free experience good enough that they keep playing. This challenge is crippling to the game itself. It is impossible to make a game as fun as it could be for both paying and non-paying players. At least one of those groups gets a game that is less fun.
Game design is all about making a certain concept as much fun as possible. By tweaking things like difficulty, flow, reward systems, variation and complexity the game designer tries to create the best experience possible. This "best experience" is an invisible target: you can never know whether you have reached it, or whether tweaking some things would make the game slightly better. It is also something that differs depending on the target audience. Some players like a challenge, others like a more relaxed experience. Some players want to drown all their time in a virtual world, others want a short and condensed experience.
The amount of "fun" in a game can be envisioned as a graph. Design the game in a certain way and you are at the very top of the graph, at the most fun experience. During development you try to tweak the game to get closer and closer to that very top, to that ultimate game. This is of course a theoretical graph: you can never know exactly how it runs. Also, there are many peaks, for the many different game concepts possible and for many different target audiences.
When designing a free to play game, the game designer looks for the best experience, just like when designing a 'normal' paid game. However, when designing for free to play the game designer needs to juggle two balls: some players pay money, others do not, and both groups need to get a good game. Especially the progress and reward structures in the game become very different for paying players. Non-paying players usually get very slow progress, while if you pay you immediately jump ahead. For example, in The Simpsons: Tapped Out you can wait many hours for a building to complete, or pay some real money to have it finished immediately.
Designing a good progress and reward structure is very important for most games. A good RPG usually becomes much less fun if you unlock new skills at half the speed, since it becomes too much of a slow grind. Unlocking things twice as fast does not make a good RPG better either: the player will feel less satisfaction when getting something new, will care less about each new item and might not even try a lot of them because they unlock so quickly. More rewards is not automatically better. There is a perfect rate of progress: not too fast, not too slow.
In most free to play games, the paying players get rewards much faster than the non-paying players. It is impossible that they are both at the top of the "fun" curve. So the designer gets a choice: make them both a bit less fun, or make one of them the ultimate experience and the other a lot less fun. In other words: it is impossible for a free to play game to make both paying and non-paying players have the ultimate experience.
This argument is not just valid for reward structures. It also works for all other aspects of the game: whenever gameplay is sold with real money, it is impossible to make that gameplay perfect for both non-paying and paying players.
The second reason why free to play games cannot achieve the best experience possible is that they are constantly nudging the player towards doing something they don't want to do. Players want to play a game, they don't want to spend money. They might be willing to spend money, but most players would rather not.
This means that the average free to play game is full of things that try to push the player away from doing what he wants to do, pushing the player towards paying real money. This can again be seen in an example from The Simpsons: Tapped Out: when you try to build something with in-game currency, the game often first lists all the items that you can only build with real money. You need to scroll through long lists of things you cannot build, until you get to the things that you can. In a 'normal' game, the game designer would design these menus to help you find what you want to build as quickly as possible. Here the game does the very opposite because it needs to tease you with all these items that it wants you to pay real money for.
Of course the player needs to pay for paid games as well, but in a paid game she pays up front, outside the game. After that the game tries to give here the best experience it can, instead of all the time trying to sell her something.
The above arguments do not mean that free to play games cannot be fun. I imagine that some readers might want to counter my arguments by giving examples of free to play games that are fun. However, my point is not that free to play games cannot be fun. My point is that free to play games could be more fun if they were not damaged by the free to play design.
Despite these problems free to play can still sometimes be a good idea. Especially multiplayer games can sometimes benefit greatly from free to play. This is because multiplayer games automatically become more fun when more people play them. The more players there are, the better the game can match players of similar skill to play together. The more players, the better lag can be reduced by matching those who are geographically close to each other and the higher the chance that your friends are also playing so you can play together with friends instead of strangers. With more players the game can also offer more game modes while still making sure everyone immediately finds opponents to play with.
In short: multiplayer games are better when more people play them. Free to play generally draws a larger crowd and thus often improves the game. So despite that the free to play model damages the game itself, the improvement from having more players might mean that the total effect of free to play can be a plus to such games.
Free to play and microtransactions are also sometimes needed purely from a business perspective. In some game genres and on some platforms players are so used to free to play that many simply refuse to pay upfront for a good game, even if it is a better game. In that case free to play might be the only way to make a successful game. Another business reason to include microtransactions might be that support, running servers and developing patches are all expensive to do. The developer might simply need the additional income from microtransactions to be able to keep supporting the game after launch.
Free to play games are inherently less fun because paying and non-paying players cannot both get the best possible experience, and because making money purely through microtransactions requires constantly pushing the player towards doing something she does not want to do. In case of multiplayer games having more players might add more fun than is lost due to free to play, but that doesn't change the fact that designing a game around microtransactions always damages some of the fun.
Sunday, 13 April 2014
Saturday, 5 April 2014
How we solved the infamous sliding bug
Last month we fixed one of the most notorious bugs in Awesomenauts, one that had been in the game for very long: the infamous "sliding bug". This bug is a great example of the complexities of spreading game simulation over several computers in a peer-to-peer multiplayer game like Awesomenauts. The solution we finally managed to come up with is also a good example of how very incorrect workarounds can actually be a really good solution to a complex problem. This is often the case in game development: it hardly ever matters whether something is actually correct. What matters is that the gameplay feels good and that the result is convincing to the player. Smoke and mirrors often work much better in games than 'realism' and 'correctness'.
Whenever the sliding bug happened, two characters became locked to each other and started sliding through the level really quickly. With higher lag, they usually kept sliding until they hit a wall. I have recorded a couple of mild examples of this bug, where the sliding stops quite quickly but still clearly happens.
Note the weird way in which the collision between Froggy and the worms happens.
To understand why this bug happened, I first need to explain some basics of our network structure. Awesomenauts is a purely peer-to-peer game. This means that the simulation of the game is spread out over all the players in the game: every computer is responsible for calculating part of the gameplay. Particularly, each player manages his own character. The result is that character control is super fast: your computer can execute button presses immediately and there is no lag involved in your own controls, since there is no server which has final say over your own character. Of course, lag is still an issue in interactions with other characters that are managed on other computers.
Spreading out the simulation like this is simple enough, until you starting looking at collisions. How to handle when two characters bump into each other? Luckily Awesomenauts does not feature real physics, which would have made this even more complex. Our solution is simply that each character solves only his own collisions. So if two players bump into each other, they solve only their own collision (in other words: they move back a bit to make sure they don't collide anymore). They don't interfere with the other character's position at all. This works pretty well and is very easy to build, but it does become difficult to control the exact feel of pushing a character, since lag is part of that equation.
This works because normally both players will try to resolve their collision in the opposite direction: the character to the right will move to the right and the character to the left will move to the left, thus moving them away from each other.
Which brings us back to the sliding bug. This bug happens when the computers disagree on who is standing to the right and who is standing to the left. If both computers think their player is standing to the right, then they will both try to resolve the collision by moving to the right. However, since they both move in the same direction the collision is not actually solved, so they keep sliding together until they hit a wall.
It is clear how this would cause sliding, but why would the computers disagree on who is standing to the right? This requires both lag and a relatively rare combination of timing and positioning. This is a difficult one to explain, so I'll first explain it in words and then in a scheme. I hope the combination makes it clear what is happening.
Let's look at the situation when two players are both moving to the right. Lonestar is in front and Froggy is behind. Froggy is moving faster, so Froggy is catching up with Lonestar. Now Froggy jumps and lands on top of Lonestar. Because of lag, the jumping Froggy sees a version of Lonestar that is slightly in the past. Since Lonestar is moving to the right, his past version is still a bit more to the left. The resulting positioning is such that Froggy thinks he is further to the right than Lonestar, so Froggy starts resolving his own collision to the right. Lonestar on the other hand sees a past version of Froggy (again because of lag) and thinks he himself is to the right. The lag makes both Froggy and Lonestar think they are on the right side.
We originally thought this would be a very rare bug, but in practice it turns out that it happened often enough that most Awesomenauts players encountered it occasionally. In fact, there was one top player who was able to aim Froggy's Dash so well that he could trigger this bug almost every time. He used it to attach his opponents to him to do maximum damage with the Tornado after the Dash. Impressive skills! Gameplay mechanics that are so difficult to time are cool because they raise the skill ceiling in a game, but it was a bug so we did want to squash it.
Since we thought it was rare and since we couldn't think of an obvious solution, we first ignored the bug for quite a while, until a couple of months ago I managed to finally come up with an elegant solution. Or at least, so I thought...
The solution I came up with was to turn off collision handling for one of the players whenever the sliding bug occurs. This way they stop sliding together, and the character who still handles collisions will resolve the collision for both of them by moving himself a bit further than he normally would. The collision is only turned off between these two characters and only for a short amount of time.
This requires knowing when the bug is happening, which is not obvious because the bug is happening on two different computers over the internet. To detect occurrences of the bug we added a new network message that is sent whenever two players collide. The player with the lowest objectID sends a message to indicate which side he believes he is on. This is a very simple message, simply saying "I am Froggy, I am colliding with Lonestar and I think I am to his right". Lonestar receives this message and if it turns out to be inconsistent with what he thinks is happening, then Lonestar turns off his own collision handling and lets Froggy resolve the collision on his own.
This is simple enough to build and indeed solves the basic version of the sliding bug, but it turned out to feel pretty broken. There are two reasons for this. The first is that in the above situation, if often happens that a character starts resolving his collision in one direction, and then in the other direction. This felt very glitchy, as the character moved in one direction for a bunch of frames and then suddenly moves in the other direction.
The second and bigger problem is that our collision resolving is done at a relatively low speed. We do this deliberately, because this way when you jump on top of a character, it feels like you slide off of him, instead of instantly being pushed aside. This is a gameplay choice that makes the controls feel good. However, this means that collision resolving is not faster than normal walking, so it is possible for Lonestar to keep walking in the same direction as in which Froggy is resolving the collision. This way the collision is never resolved and Froggy keeps sliding without having control. This may sound like a rare situation, but in practice player behaviour turned out to cause this quite often, making this solution not good enough.
Seeing that this didn't work, I came up with a new solution, which is even simpler: whenever the sliding bug happens, both characters turn off their collision, and it is not turned on again until they don't collide any more. In other words: we don't resolve the collision at all!
This sounds really broken, but it turns out that this works wonders in the game: players rarely stand still when that close to an enemy, so they pretty much instantly jump or walk away anyway. In theory they could keep standing in the same spot and notice that the collision is not resolved, but this hardly every happens. Moreover, even if it does happen, it is not that much of a problem: teammates can also stand in the same spot, so two enemies standing in the same spot does not look all that broken.
This solution has been live on Steam for over a month now and as far as we know, it is working really well.
As you might have noticed, this has been a pretty long and complex blogpost. The sliding bug is just one tiny part of network programming, so I hope this makes it clear how complex multiplayer programming really is. There are hundreds upon hundreds of topics at least as difficult as this one that all need to be solved to make a fast-paced action MOBA like Awesomenauts. Also, this solution is a very nice example of something that seems really wrong and way too simple from a programming standpoint, but turns out to work excellently when actually playing the game.
Whenever the sliding bug happened, two characters became locked to each other and started sliding through the level really quickly. With higher lag, they usually kept sliding until they hit a wall. I have recorded a couple of mild examples of this bug, where the sliding stops quite quickly but still clearly happens.
Note the weird way in which the collision between Froggy and the worms happens.
To understand why this bug happened, I first need to explain some basics of our network structure. Awesomenauts is a purely peer-to-peer game. This means that the simulation of the game is spread out over all the players in the game: every computer is responsible for calculating part of the gameplay. Particularly, each player manages his own character. The result is that character control is super fast: your computer can execute button presses immediately and there is no lag involved in your own controls, since there is no server which has final say over your own character. Of course, lag is still an issue in interactions with other characters that are managed on other computers.
Spreading out the simulation like this is simple enough, until you starting looking at collisions. How to handle when two characters bump into each other? Luckily Awesomenauts does not feature real physics, which would have made this even more complex. Our solution is simply that each character solves only his own collisions. So if two players bump into each other, they solve only their own collision (in other words: they move back a bit to make sure they don't collide anymore). They don't interfere with the other character's position at all. This works pretty well and is very easy to build, but it does become difficult to control the exact feel of pushing a character, since lag is part of that equation.
This works because normally both players will try to resolve their collision in the opposite direction: the character to the right will move to the right and the character to the left will move to the left, thus moving them away from each other.
Which brings us back to the sliding bug. This bug happens when the computers disagree on who is standing to the right and who is standing to the left. If both computers think their player is standing to the right, then they will both try to resolve the collision by moving to the right. However, since they both move in the same direction the collision is not actually solved, so they keep sliding together until they hit a wall.
It is clear how this would cause sliding, but why would the computers disagree on who is standing to the right? This requires both lag and a relatively rare combination of timing and positioning. This is a difficult one to explain, so I'll first explain it in words and then in a scheme. I hope the combination makes it clear what is happening.
Let's look at the situation when two players are both moving to the right. Lonestar is in front and Froggy is behind. Froggy is moving faster, so Froggy is catching up with Lonestar. Now Froggy jumps and lands on top of Lonestar. Because of lag, the jumping Froggy sees a version of Lonestar that is slightly in the past. Since Lonestar is moving to the right, his past version is still a bit more to the left. The resulting positioning is such that Froggy thinks he is further to the right than Lonestar, so Froggy starts resolving his own collision to the right. Lonestar on the other hand sees a past version of Froggy (again because of lag) and thinks he himself is to the right. The lag makes both Froggy and Lonestar think they are on the right side.
We originally thought this would be a very rare bug, but in practice it turns out that it happened often enough that most Awesomenauts players encountered it occasionally. In fact, there was one top player who was able to aim Froggy's Dash so well that he could trigger this bug almost every time. He used it to attach his opponents to him to do maximum damage with the Tornado after the Dash. Impressive skills! Gameplay mechanics that are so difficult to time are cool because they raise the skill ceiling in a game, but it was a bug so we did want to squash it.
Since we thought it was rare and since we couldn't think of an obvious solution, we first ignored the bug for quite a while, until a couple of months ago I managed to finally come up with an elegant solution. Or at least, so I thought...
The solution I came up with was to turn off collision handling for one of the players whenever the sliding bug occurs. This way they stop sliding together, and the character who still handles collisions will resolve the collision for both of them by moving himself a bit further than he normally would. The collision is only turned off between these two characters and only for a short amount of time.
This requires knowing when the bug is happening, which is not obvious because the bug is happening on two different computers over the internet. To detect occurrences of the bug we added a new network message that is sent whenever two players collide. The player with the lowest objectID sends a message to indicate which side he believes he is on. This is a very simple message, simply saying "I am Froggy, I am colliding with Lonestar and I think I am to his right". Lonestar receives this message and if it turns out to be inconsistent with what he thinks is happening, then Lonestar turns off his own collision handling and lets Froggy resolve the collision on his own.
This is simple enough to build and indeed solves the basic version of the sliding bug, but it turned out to feel pretty broken. There are two reasons for this. The first is that in the above situation, if often happens that a character starts resolving his collision in one direction, and then in the other direction. This felt very glitchy, as the character moved in one direction for a bunch of frames and then suddenly moves in the other direction.
The second and bigger problem is that our collision resolving is done at a relatively low speed. We do this deliberately, because this way when you jump on top of a character, it feels like you slide off of him, instead of instantly being pushed aside. This is a gameplay choice that makes the controls feel good. However, this means that collision resolving is not faster than normal walking, so it is possible for Lonestar to keep walking in the same direction as in which Froggy is resolving the collision. This way the collision is never resolved and Froggy keeps sliding without having control. This may sound like a rare situation, but in practice player behaviour turned out to cause this quite often, making this solution not good enough.
Seeing that this didn't work, I came up with a new solution, which is even simpler: whenever the sliding bug happens, both characters turn off their collision, and it is not turned on again until they don't collide any more. In other words: we don't resolve the collision at all!
This sounds really broken, but it turns out that this works wonders in the game: players rarely stand still when that close to an enemy, so they pretty much instantly jump or walk away anyway. In theory they could keep standing in the same spot and notice that the collision is not resolved, but this hardly every happens. Moreover, even if it does happen, it is not that much of a problem: teammates can also stand in the same spot, so two enemies standing in the same spot does not look all that broken.
This solution has been live on Steam for over a month now and as far as we know, it is working really well.
As you might have noticed, this has been a pretty long and complex blogpost. The sliding bug is just one tiny part of network programming, so I hope this makes it clear how complex multiplayer programming really is. There are hundreds upon hundreds of topics at least as difficult as this one that all need to be solved to make a fast-paced action MOBA like Awesomenauts. Also, this solution is a very nice example of something that seems really wrong and way too simple from a programming standpoint, but turns out to work excellently when actually playing the game.
Subscribe to:
Posts (Atom)