Sunday, 2 February 2014

The Maarten Principle: a golden rule of planning

I have been making schedules and work estimates at Ronimo for years now and although I won't claim that they are always correct, I have definitely learned a lot so far. One of the most important things I learned is what I like to refer to as The Maarten Principle, which I would like to discuss today. The Maarten Principle is named after Ronimo programmer Maarten who first coined this concept.

An important part of planning is trying to figure out how long it is going to take to build something. Scrum extremists might have you believe that you don't need to do this since your game is always finished and just getting better over time, but in practice there are a lot of things that you just have to do to make the game releasable. Implementing console certification requirements is a good example of a task that cannot be skipped, but usually there is also a vision for the game that just requires a certain amount of features and assets to make it a good game.

To have any idea how much work is left to finish the game, we need some kind of schedule. At Ronimo the core of the schedule is basically just a long list of everything that still needs to be done. We might change this schedule at any time, but we try to always keep it up to date with our current plans for the game.

To use this list to estimate how much work is left, each task needs an estimate of how long it is going to take to complete. Coming up with good estimates is the most difficult part of making a schedule, and we have gathered a bunch of tricks and guidelines through the years to help us make decent assessments. Unfortunately our estimates are still often not correct, but at least they are a lot better than they would be without these guidelines.

The most important of these guidelines is The Maarten Principe, the topic of today's blogpost. Its basic formulation is sarcastic:



The more elaborate way of saying the same thing is this:



The point of this rule is that when estimating a complex task that takes a lot of work (like for example implementing matchmaking in an online multiplayer game), it is impossible to make a decent estimate for the task as a whole. Two weeks feels like a long period in which you can do a lot of work, so for many big tasks it feels like it can be completed within two weeks, even if the feature in practice turn out to take much longer to implement. Distinguishing between tasks that take two weeks, three weeks or one month is incredibly difficult.

We learned this lesson the hard way. Halfway development of Awesomenauts we made a task overview with all the coding work we had left. This schedule contained a lot of large tasks (PS3 matchmaking, 360 matchmaking, bandwidth optimisation, performance improvements, menus, etc.) and in the end every single one of them turned out to take way longer than we had estimated in that overview. Development of Awesomenauts turned out to take three full years while we had planned this to be much less, so this was a huge mistake that back then caused our studio a lot of problems.

The problem with this schedule became very clear whenever we arrived at an actual task. Say for example we had estimated that implementing menus took 10 days of work (I don't know the exact estimate we had at the time, this is just an example). As soon as someone was to actually work on this task, we split it up into all the screens the menu needed and all the general systems we needed to make menu screens. We then estimated how much time each of these smaller tasks would take. It turned out that they added up to much more than the original estimation for the job as a whole!

This is a pattern that we have seen time and again: whenever a big task is split into smaller tasks, it turns out to take much more time than expected, often twice as much or even more. If we split up the task into smaller subtasks much earlier, we get a way better estimate of how long it will really take to implement. In our experience the problem is not so much that the task is too far away to give a good estimate, but more that the task is too big to grasp its complexity well enough to give an estimate.



Since I have so far mostly been responsible for the coding schedules at Ronimo, one might assume that this is just a problem with programmers (or maybe even just a problem with programmers at Ronimo). However, I recently helped our lead artist Gijs to make the art planning and I saw the exact same thing happening. We wanted to split several big tasks of dozens of days each into smaller tasks, and adding those all up immediately grew the total estimated time a lot. Just as it does with the coding estimates, splitting a big task into smaller subtasks immediately grew the expected time to finish it.

I still cannot claim that The Maarten Principle goes for any game studio, but I can definitely say that it does not apply only to programmers.

Based on The Maarten Principle we always try to split bigger tasks into ones that take at most 3 days to complete. At a maximum of three days per task it is still very doable to imagine all the things that need to be done to complete that task, and thus to make a decent estimate of how long it takes to complete. For tasks bigger than that, we try to split them into smaller tasks until each is at most 3 days. Of course this is sometimes impossible to do, as more information might be needed to have any idea how to split a big task. But in practice, most tasks can be split into smaller tasks quite easily.



Following The Maarten Principle does not grand one the power to make perfect schedules, but this rule does help us a lot in making better estimates!

Saturday, 25 January 2014

Concept art can be raw: early designs for AI Station

When people think of concept art, they usually think of the super slick artworks that AAA games release as part of their marketing. However, making such perfected art takes a lot of time and is very inefficient when the goal is to explore many concepts. Today I would like to show the concept art that our artists made for the map AI Station 404 in Awesomenauts, as it is an excellent example of how rough real concept art can be.

click for high resolution

A couple of months ago I was at a presentation at the Control Conference where concept artist James Daly showed their concept art for one of the Transformers games. Every image looked mindblowingly awesome (have for some examples a look at this, this and this), but in a sense this is also weird: it seemed like concept artists only make superbly detailed and shaded paintings.

Presentations like that give the impression that that is how concept art works, but in practice making such high quality art is highly inefficient. The goal of concept art is not to make pretty pictures, but to design things for the game, to explore. If every image needs to be so detailed, then there is much less room for exploration than if an artist instead creates many simpler, quicker sketches and tries out many things that way. I suppose Daly and his team also made tons of quicker sketches and designs, but I don't remember seeing any of those in his presentation.

Of course such slick concept art does serve several purposes: it can be used in marketing and to make people enthusiastic. I imagine that any art that needs to be approved by a gigantic IP holder like Hasbro (for Transformers) has to be extra slick just to convince Hasbro to approve the designs. However, in practice most concept art is not intended for marketing and can thus be much simpler. Another reason why concept art might be so detailed is to help 3D artists, especially if the artist lacks imagination or is outsourced off-site.

The concept art that the artists at Ronimo make is usually not intended for outsiders, and only for exploration and internal communication. That means that it is often rough, but at the same time communicates the core ideas really well. The result is series of pictures that explore ideas in all kinds of directions. Such series are often really awesome to see, especially for the great variation in colours and shapes they play with. Good artists can create magic with just a few rough lines. An excellent example is this set of designs that was made for the level AI Station 404 in Awesomenauts:

click for high resolution

These images were drawn halfway development of Awesomenauts by Tristan Kok, who did an internship at Ronimo at the time. Below are all of them individually and at full size. When you look closely, you can see that only as much has been drawn as is needed to communicate the idea and colour scheme of the map. The right half of the map is often even left out, and objects are drawn very roughly.

1. click for high resolution

2. click for high resolution

3. click for high resolution

4. click for high resolution

5. click for high resolution

6. click for high resolution

7. click for high resolution

8. click for high resolution

9. click for high resolution

10. click for high resolution

11. click for high resolution

I think the final choice our art team made was to combine the shapes from number 8 and the colour scheme from number 10. Some of the brownish ones also look pretty cool in my opinion (like numbers 3 and 5), but would not have added enough variation because their colour schemes are similar to the then already existing Sorona map.

Which of these designs do you like best?

Another thing you can notice here is that the level geometry is still visible in many cases. These images were drawn on top of a screenshot of the level as our game designers had made it at the time. At Ronimo most ideas start with a gameplay idea and the art is only made after we have played it and concluded that it makes for fun and interesting gameplay. A while ago I wrote a blogpost about how our artists usually jump in when the gameplay is already set: Extreme Transformation Of Nauts During Development.

The art is based on the gameplay, so what better way to draw it than on top of an actual screenshot of that gameplay? Beginning concept artists often forget this link between art and game: they draw objects from their most awesome angle, instead of from the angles under which the objects are actually seen in the game. When designing a car for a racing game, the most important thing is what it looks like from the back since that is how the player will be viewing it 99% of the time. Yet many beginning concept artists focus only on the front, since that is where a car looks most awesome.

After some more concepting the level went into production. Art for it was gradually implemented into the playable level. Some shots didn't work immediately, so our lead artist Gijs grabbed a bunch of screenshots of the art that was there already and started drawing on top of them. Again: rough, drawing only as much as is needed to communicate the idea and style. A smaller studio like Ronimo does not have the limitless resources that AAA studios seem to have, so we need to work efficiently. Spending days on making awesome concept art while something simpler would suffice is not efficient.

click for high resolution

click for high resolution

click for high resolution

Gijs also drew a concept for the central machine in the level, as you can see below. In the bottom right this image even still shows the selection boxes of the objects that happened to be selected in our editor when the underlying screenshot was captured. I could personally never work like that, since I am way too much of a perfectionist. However, working so roughly is highly efficient and very fast, so this is much better than spending more time on perfecting an image while it already contains everything that is needed to communicate the point. (Another reason I could not work like this is that I am a programmer and am horrible at drawing...)

click for high resolution

I hope these images make it clear that concept art does not have to be super slick and detailed to work. The key thing is realise what the goal of the concept art is. If it is marketing or persuading people, then an image might have to be as awesome as possible. But if the goal is actual concepting, then it is much more important to explore many directions than to make slick images. As soon as the image communicates what it was intended for, there is no real need to add more detail.

Also, I personally think that despite the roughness, these images look incredibly cool, so I hope you enjoy viewing them as much as I do!

Sunday, 19 January 2014

How chance in games is rarely just a roll of the dice

Games contain many forms of chance. From simply selecting a random character or level to play, to random pick-ups and even completely procedural worlds: chance, luck and randomisation play a huge role. While developing Awesomenauts we have experienced this first hand, especially in the various versions of Leon's crits, which has been changed several times in patches during the past 1.5 years. Last week I mostly talked about the psychology of crits, and today I am going to look at chance in games in general.

When a programmer is told to implement a random for something, he will often simply use std::rand() or something similar and that's it. However, in practice it turns out that both players and designers rarely really want a truly random chance.

A good example of this can be found in level selection in Awesomenauts: in a practice match there are four levels to chose from, and there is a 'random' button to select random levels. With a true random, the random button might result in playing the same level several times in a row. There is a small chance that a player gets the same level 4 times in a row (1.5625%, to be exact), and even 10 times the same level in a row is possible. When this happens, both players and designers start to voice complaints like “the random is not random, it always selects the same map”. Of course, in a truly random dice roll, the chances of throwing a number are completely independent of what was thrown before that, so even a million times the same value in a row can happen. The chance of that happening is just really small.



So what every game programmer needs to realise, is that when a designer asks for random, he rarely asks for a complete random. The random usually needs some extra logic to keep unwanted situations from happening. In Awesomenauts, the game remembers which map you last played and does not select it again for the next match (although if you join matches, you might still join several matches in a row with the same map). Similarly the music player remembers the last four songs it played and does not select those again when it chooses the next song to play. And I imagine that in a random dungeon generator it is likely not desirable to put instances of the same room next to each other.

An important part of random is human perception. Humans are exceptionally good at recognising patterns. In fact, humans are so good at this that they often recognise patterns where there are none. Noteworthy situations are remembered, while other situations are not. Astrology is for a large part based on this. If only one out of ten predictions turns out to be correct, many people will tend to remember that one correct prediction and not the nine false ones, making it possible for charlatans to pass for real predictors of the future.

Something similar goes for the perception of random in games. We have had numerous reports from players that the map they dislike most is selected much more often by the random map selection. However, every player who reports this reports it for a different map, and our random is just fine. What really happens there, is that people remember every time they get the map they don't want, and don't really remember what other maps they played recently.

Human psychology is therefore an important part in designing random. A great example of this can be found in one of my favourite game series: Civilization. Sid Meier did a hilarious presentation on how they modified their random in Civilization Revolution. One of the things they did is that if a unit has 90% chance to win, this is treated as 100%, because it turned out that it always felt unreasonable to lose when the win chance was 90%. Another trick they did is that if a number of 50% battles in a row are all lost, then at some point the next one is automatically won, because it simply feels unfair to lose so often in a row.

Of course, with a mechanic like that it is important to either keep players from knowing it works like that, or to keep a bit of random in there, because otherwise knowing how this works will result in exploitable tactics. If there is one thing we learned during development of Awesomenauts and Swords & Soldiers, it is that if something can be abused, it always will!



Inspired by the Civilization article, we started playing with Leon's crit chance. The original implementation we had for this was simply a clean chance. However, this sometimes resulted in having two or three crits in a row, which is incredibly powerful. Dying from this felt unfair, because it did so much damage that there was little opportunity to get away from it.

To solve this we modified the crit chance to never happen twice in a row, and also to never fail ten times in a row. This way the crits are still random, but the situations that feel unfair don't happen anymore.

This worked fine and had the desired result, but what we did not realise is that it massively changes the actual crit chance! With a 15% crit chance, the chance of it missing 10 times in a row is a surprisingly high 19.7%. Adding a guaranteed extra crit so often increases the crit chance significantly! So in that particular patch we accidentally buffed Leon a lot, making him pretty overpowered.

We did not realise we had done this until players started counting. They quickly noticed that Leon had become a lot stronger, but we simply didn't believe them. To convince us that something was wrong, a couple of players performed several hundred attacks in a row and counted how many crits they got. Even then we still didn't believe them at first, but once we understood what was happening here, we modified the crit chances to be the same as before again, including the extra rules for consecutive hits.


Image by Awesomenauts player 'Offline' (I think).

This brings me to the end of this blogpost. As the various topics I have discussed today have shown, there is much more to chance, luck and random in games than just using pure random functions. Whenever random is involved, the designer and programmer should always consider what they want exactly, since in practice it turns out that a true random is quite rarely wanted.

Friday, 10 January 2014

The surprisingly many subtleties of designing crits

Crits (or "critical hits") seem like a pretty straightforward topic: there is a certain chance that you deal more damage, and that's about it. It is easy enough to calculate average damage and balance based on that, and beyond that it seems like just a choice whether your game has weapons with crits or not. However, in practice it turns out that there are a lot of subtleties to crits that are not immediately apparent. In Awesomenauts we have had various implementations of crits and each time more subtleties surfaced. So today I would like to talk about their many aspects.

Crits can be applied to any weapon or attack and their core element is chance: there is a small chance that a weapon does extra damage. Usually this chance is low, below 30%. Instead of damage, the crit might also add other effects, like a stun or knockback. Crits are mostly seen in RPGs, where they are a nice way of spicing up the weapon variation. A sword that does 10 damage feels quite different from a sword that does 7 damage and has a 25% chance of doing 19 damage. The average damage output of these two swords is the same, but they feel and play very differently. Crits also add extra variation to levelling and upgrading: one can upgrade not only the base damage, but also the crit damage and the crit chance.



Crits are often a fun and interesting mechanic. While a normal sword always has the same result and is thus entirely predictable, a sword with a crit chance makes the player curious for every next hit. “Will it crit?! I hope it will crit!”

Adding chance to a game adds unpredictability. Having a lot of unpredictability greatly changes the feel of a game. A great example of this is Mario Kart. In Mario Kart when you grab a pick-up you usually get a random item and the effectiveness of the items varies massively. Picking up the right item at the right time often makes the difference between winning or losing the game. This is great for beginning players: even if they are playing against much better opponents, there is still a chance that the beginner might win because she has some lucky pick-ups. This makes a world of difference in comparison to purely skill-based games, in which the beginner will basically always lose until she becomes as good as her opponents.



Luck also has a soothing effect. If you lose because your opponent was better, then the player can do little but blame her own lack of skill. This can be frustrating. On the other hand, if luck is involved, the player can always blame that, which is much easier to accept. Most losing players need scapegoats to be able to cope with their own failure. Luck is a great scapegoat, just like the referee's mistakes are in soccer.

Knowing that players need a scapegoat actually helps in understanding player feedback. Any competitive online game has players complaining about balance, and as a developer it is important to realise that part of that is completely unrelated to the actual balance, and is just players needing a scapegoat to be able to accept losing that match. (By which I am of course not suggesting that balance in Awesomenauts is perfect. I am merely saying that a part of balance complaints are caused by players needing a scapegoat instead of actual problems in the balance.)

The above text may make it sound like crits only have benefits, but this is absolutely not the case. The big problem with crits and luck in general is that they take away part of the competitive nature of a game. If a player invests hundreds of hours into becoming highly skilled at a game, then losing a match because the opponent got lucky just plain sucks. Competitive players generally hate luck with a passion. This is the reason why in the end, we removed Leon's crits and turned them into a completely predictable consecutive-hit system.



Bluntly summarising today's blogpost, one could claim that crits and luck make a game more casual, while complete predictability make it more hardcore and competitive.

The title of this blogpost said I was going to talk about the many subtleties of crits, but it turns out that there are so many that I cannot cramp it all into one single blogpost. Therefore I will come back to this topic next week and talk about how luck in games is rarely just a roll of the dice, and how modifying crit chances in the wrong way can be painfully destructive to balance.

Edit: Here's a link to that next blogpost: How chance in games is rarely just a roll of the dice

Saturday, 4 January 2014

Bitcrunching numbers for bandwidth optimisation

An important part of making a complex multiplayer game like Awesomenauts is optimising bandwidth usage. Without optimisations, just sending position updates for one character to one other player already costs 240 bytes per second (30 updates per second at 4 bytes each for both X and Y). And this is just a fraction of what we need to send: Awesomenauts can have up to 35 characters running around the game world, and we need to synchronise much more than just their positions. As you can see, bandwidth usage quickly spirals out of control, so we need to be smarter than just naively sending all the data all the time.

In the many months we spent on bandwidth optimisation, we employed lots of different techniques. The one I would like to talk about today can massively decrease bandwidth by crunching numbers on the level of individual bits. This technique not only worked great for the multiplayer implementation of Awesomenauts, but I am now also using this extensively for reducing the size of our replays.

Let's have a look at the core idea here. Storing one unsigned int normally costs 32 bits. In this we can store a value in the range of 0 to over 4 billion. However, we rarely need a range as big as that. For example, the amount of Solar you collect during an Awesomenauts match rarely goes over 5,000. In a really long match we might go past that, so let's bet on the safe side and say we want to store Solar values up to 10,000. This could be stored in 14 bits, since 2^14 = 16,384. That is less than half of the normal 32 bits used for a value like this!

Using too many bits is not a problem in memory since modern computers have plenty of that. But when sending the Solar over the network, we would like to use only those 14 bits we actually need. However, normally we can only handle data on a byte level, not on a bit level, so the best we can easily do is to store this in two bytes (16 bits).

What we need here to solve this is a bitstream, something that we can use to group together a lot of values on a bit-level. This way we can just grab a block of memory and push in all the values we want to send over the network. The idea is quite straightforward, so let's jump right in and have a look at how one could use that:

//Class for pushing bits into a block of memory
class BitInStream
{
public:
    BitInStream(char* data);
    void addUnsignedInt(unsigned int value, unsigned int numBits);
    void addBool(bool value);
};

//Class for reading bits from a block of memory
class BitOutStream
{
public:
    BitOutStream(const char* data);
    unsigned int getUnsignedInt(unsigned int numBits) const;
    bool getBool() const;
};

//Example of using these
void main()
{
    //The bits are stored in this
    char data[4];
 
    //Example of writing some values
    BitInStream bitInStream(data);
    bitInStream.addUnsignedInt(solar, 14);
    bitInStream.addUnsignedInt(itemsBought, 6);
    bitInStream.addBool(isAlive);
    bitInStream.addUnsignedInt(damageDone, 10);
 
    //Read back values
    BitOutStream bitOutStream(data);
    solar       = bitOutStream.getUnsignedInt(14);
    itemsBought = bitOutStream.getUnsignedInt(6);
    isAlive     = bitOutStream.getBool();
    damageDone  = bitOutStream.getUnsignedInt(10);
}

The details of actually implementing the bitstreams itself is too much for this blogpost, so I will leave that as a fun exercise for the reader. Hint: you can use bitwise operators like |, ‹‹, &.

When looking at this code there are a number of observations to make. First is that I am actually using only 31 bits while storing them in 4 bytes. In other words: I am wasting 1 bit here! This is something that almost always happens when using bits: at some point they need to turn into bytes, since that is what network packets are measured in, and we usually waste a couple of bits there. This loss can be decreased by using larger bitstreams with many more values in them.

A much more important realisation here is how easy it is to break this code. If I read back the solar with the wrong number of bits, then not only will the solar be complete garbage, but also all values after it. The same happens if I accidentally read back values in the wrong order, or forget to read one. The compiler will not warn you of any of these things and debugging on a bit-level is difficult, so this produces extremely stubborn bugs! Another easy mistake is to use too few bytes for the data, resulting in buffer overflows and thus memory corruption, or to use too many bytes, resulting in wasting bandwidth. In short: use bitstreams only when you really need them and be extremely careful around them!

So far we have only stored the easy kinds of data: bools and unsigned ints translate very easily to bits. However, many things in a game are floats. When using an unsigned int, taking just its first 10 bits results in a valid number, just with a smaller range. But with a float taking those same 10 bits results in nonsense. How can we send floats with arbitrary numbers of bits?

The trick here is rather simple. A float has a number of properties that we usually don't need. Floats have very high precision near 0, but when storing a position, we want the same precision everywhere. Floats also have an extremely large range, but for that same position we already know the size of the world and we don't need to be able to store values outside that range.



Knowing these things we can store positions (and most other floats) in a different way. Levels in Awesomenauts happen to all be in the range -10.0 to 30.0. Knowing this we can just store the x-position as an unsigned int with an arbitrary number of bits. If we want to store a position in 8 bits, then the lowest value (0) means position -10.0, and the highest value (255) means position 30.0. Values in between are just interpolated. This is a simple and very effective trick. Depending on how much precision we need, we can use more or less bits.



When synching over the network we actually don't need all that much precision, since the receiver is not using the position for a physics simulation. He mostly just uses it for visualisation and checking whether a bullet hits. So in Awesomenauts we use 13 bits for synching the x-position and another 13 bits for the y-position, which is a lot less than the normal 32 bits each would need as a float!

The same idea can be applied to many other things that are also floats and for which we know the range. Some things even need extremely little precision. For example, the health of other players is only visualised in their healthbar, so we only need to synch as many bits of that as are needed to make the healthbar look correct. Since healthbars are usually in the order of 100 pixels wide, we can store health in 7 bits, even if the actual range of the health might be 0.0 to 2000.0. With 7 bits our for that range would be only 15.625, but more isn't needed because the difference is not visible in the healthbar anyway. The simulation is not influenced at all by this, since the owner of the character still stores the full precision float for the health.



Using tricks like these we managed to get the bandwidth usage of Awesomenauts down to around 16 kilobyte per second. This is the total upload needed at the player who manages bots and turrets. The five other players in a match don't manage those bots and turrets, so they use far less bandwidth still. For comparison: our very first network implementation in the Awesomenauts prototype we had four years ago used around 50x (!) more bandwidth. Bit-crunching numbers as explained in this blogpost is just one of the many tricks we used to decrease bandwidth, but it was definitely one of the strongest!

Thursday, 19 December 2013

Camera mapping a comic: the Ward trailer

It has been a while since I dabbled in the awesome fun of camera mapping. Recently I bumped into a good reason to get back to that invigorating topic: the comic Ward was released. Marissa Delbressine was working on a trailer for her comic and she thought having a camera mapping of Ward's cover would be an awesome addition. Marissa threw me a pretty smile to which I couldn't say 'no', so I went to work on it. (Marissa happens to be my girlfriend, so I guess without the pretty smile I couldn't have said 'no' either... ;) )

Here is a compilation of the shots I made of the cover of Ward, plus shots of the meshes used to make this scene:



Marissa used a couple of these shots in the complete Ward trailer, which you can see below. Note that most of this trailer is not camera mapped: I was personally only involved in the shots at 0:43 and 1:12. All the 2D art and the rest of this trailer were made by Marissa and co. I think the result is great: making a trailer for something as static as a comic is difficult and I think Marissa did a great job of bringing it to life. It helps if you know Dutch and can read the text, though... Anyway, here is the complete trailer:



It has been several years since I last wrote about camera mapping on this blog, so let's do a quick recap of what this technique is. The idea is to project a 2D image onto a 3D model, so that you can do 3D camera movements through this 2D image. To do so, you have to first split the image into layers, and then create simple, rough 3D models to represent the objects in the image. Here is how this was done for Ward:


The process of creating the camera mapping of Ward. I only did the 3D parts: colours were done by Shanna Paulissen and splitting into layers and extending them by Iris Adriaansz.

Those who make 2D animations will likely recognise most of this: camera mapping is a more advanced version of a technique that is often used by 2D animators; they also split the scene in layers to create a 3D effect. The difference between this simple layers approach and full camera mapping is that with camera mapping the 3D models aren't just planes: they are real 3D objects that roughly mimick the shape of the 2D objects. This makes the 3D camera movements much more convincing, since the scene is not just a collection of cardboard planes anymore.

The main reason I think camera mapping is such an exciting technique, is that it allows for 3D graphics to achieve unique 2D looks. 3D graphics can look like many things, but there are very few 2D styles that normal 3D graphics can do well. The roughness of a brush or a pencil stroke is something that only really works in 2D, and camera mapping makes it possible to get that look in 3D.

Another benefit of camera mapping is that it only requires very simple 3D models. The details are all in the drawing, so you don't need to model everything and can get away with crude approximations of the real 3D models. Most work in camera mapping is in dividing the scene into proper layers in Photoshop. If the artist already works in layers, this can be a relatively simple thing to do.

The big downside of camera mapping is that objects have no backside, so the camera cannot rotate all around them. In the case of games this makes camera mapping mostly useful for games with limited camera movement, like 2.5D platformers, or games with a perspective like Diablo. In fact, the awesome Diablo III uses quite a bit of camera mapping, but disappointingly refuses to use the technique to create a truly unique art style.



Since it has been so long since I wrote about camera mapping, here are the camera mappings I did a couple of years ago:


I hope to come back to camera mapping some day to create some real-time game environments with it. I already have one quite far finished, but instead of finishing it I always end up spending my spare time on Cello Fortress and writing blogposts, so I don't know when I will actually get to that.

Let's end this blogpost with some blatant marketing for Ward, which is an awesome comic and it currently available in stores in the Netherlands. Marissa drew some amazingly detailed and beautiful art for it, so check it out! Ward is only available in Dutch, and is sold in specialised comic stores and at Bol.com and in the Eppo Webstore.

Friday, 29 November 2013

First steps towards massive replays and spectators in Awesomenauts

One of the biggest challenges for us in the coming period is implementing replays and spectator mode in Awesomenauts. It might not be immediately obvious, but this is actually an incredibly complex problem to solve. We have the very first bits working now, so here is a video in which I show and explain what we have so far:



Our first target with replays is to get them working offline, so you store replays of your own matches on your own harddisk and you can email those files to your friends by hand. Storing and browsing replays through online servers comes after that and is still a long way away. We hope that the offline replays can go in beta before Christmas, but right now it seems like that might still be too early for how complex this all is.

So why are replays so difficult to build? There are a ton of reasons for this. One is that players need to be able to do live spectating. In high-level tournament matches, we currently sometimes get near to 1000 simultaneous viewers for a single match. This is on Twitch, so the bandwidth is handled by Twitch, but for our spectator mode we will need to make that possible ourselves. Handling that kind of user numbers and internet traffic is by itself already a big challenge.

Another problem is that players need to somehow get their replays to a server, live while playing. By itself this is not very difficult, but to keep this from disrupting normal online play, we need to do this in an extremely small amount of bandwidth. We are targeting to stream out a replay from one player to the server in only 1 to 2 kilobyte per second. The total size of a 20 minute match will then be around 2mb. Streaming all data in so few bits is an interesting challenge, but I think it is quite achievable.

Another problem is version management. We release lots of patches for Awesomenauts, and most patches change significant things in our gameplay logic. That means that if we rely on that gameplay logic for playing back replays, then stored replays will often not be playable anymore once we release a patch. A solution for this would be to add version management to the gameplay code, but that would add a kind a code complexity that we definitely don't want there. And I haven't even mentioned how sensitive to bugs that would be... Another solution would be to store legacy versions of the game to play older replays, but that would produce very high loading times when switching between reviews, and would mean loads of downloading to get all those older game versions.

Our solution for this version problem is to store only graphical data in the replay. This way if gameplay logic changes, it doesn't matter for stored replays, since those don't use the gameplay logic anyway. The demo shown above already works like this. However, this does mean that we cannot use any of the current gameplay code or network packages for the replays. We need to rebuild it all from the ground up in a different way. That is why the demo above still lacks animations and bullets and pickups and such: they have not been rebuilt for replays yet.

Another issue in the replays implementation is server bandwidth and loading times. If players view lots of replays, this will cost us a lot of bandwidth and thus a lot of money. Also, if players need to download the entire replay before they can watch it, then waiting times might be long. We even want players to be able to immediately skip to specific moments in the replay without downloading everything in between. With this in mind, the replay system again becomes a lot more complex.

There are several other challenges in implementing replays and spectator mode, but these are the most important. The video shown actually solves the basics of several of those already: there is quite a bit of interesting code architecture behind it. This is also why it took so long before we got anything to show at all: storing and playing character positions is by itself not all that difficult, but doing it in a way that will work with the above issues makes it a lot more time-consuming to implement. I expect I will be able to do a great talk or series of blogposts on this once the whole replays system has been built...

As a conclusion to this blogpost, I would like to say that this is a mightily interesting and fun challenge! We at the Ronimo coding team are greatly enjoying this task: coding puzzles are the best puzzles!