Friday, 24 August 2012

In Awesomenauts we have characters that can aim in all directions. How does that work? In a 3D game this would be quite straightforward: you just make animations in a couple of directions and blend those. Blending angles of bone-animations is a really simple thing. To make it easier, you might animate the upper body and the legs separately and blend those parts as well.

In 2D, however, this is a wholly different story. Awesomenauts characters don't have bones: the game simply gets a series of frames for each animation and shows those in order. So how to do this, then?

We started by having a look at several other games. An older game that solves this problem, is Abuse (1996). Looking at footage from that game, I think what they did is that the upper and lower body are animated entirely separately and then combined in the game. The legs just do the walking and jumping and such, and totally ignore the aiming. The arms have been drawn for each aiming direction they support, which I think is as least 16 directions. I get the idea they did not actually animate the arms: they just drew one frame for each direction, and then move the entire frame up and down with the lower body to keep it from being too static. Not sure if this is actually the case, but that is what I think they did.

Another solution can be found in Capsized (2011). Capsized also splits the body at the waist, but to get the aiming directions for the arms, they simply rotate the entire upper body. This is a pretty smart solution, I think, and it rotates very fluently. The character can aim in all directions with very little animation work involved. At the same time it doesn't look very natural, since the upper body very clearly just rotates as a whole, arms and head included.

Aiming animations in Capsized. Note the smart trick they did with the lower body: it contains a bent back that becomes visible when the character looks down. It also glitches a bit at the front when the character looks up, though.

Both Capsized and Abuse have in common that the character has been split at the waist. However, when we were working on this, we already had several characters that didn't have a clear waistline (like a belt or something like that), making it difficult to separate them easily. Since our artists had already rebuilt the first characters several times at that point (they were also exploring After Effects as an animation tool around that time), we decided to not do another redesign with a clear waistline, and to not rebuild the characters in After Effects for this.

By this time, for gameplay reasons we had already decided that characters could only aim in angles of 45 degrees, and could not aim backwards. So the player could aim in only 8 directions. This made the animation problem a lot simpler. We chose to simply animate the character in each of the directions. So for each animation (walk, idle, slide, jump, fall) our art team made animations in each direction. Since the player cannot aim backwards, and since some combinations cannot be done with our control scheme (like walking and aiming straight up), our art team had to make around three directions for each animation. This works great and looks very smooth, as you can see in the video below.

Animations in different directions in Awesomenauts on console. Note how having completely separate animations allowed our artists to do cool stuff like showing Lonestar's teeth and eyes or Froggy's tongue under certain angles.

However, when we got to porting for the PC version, this turned out to not work for that. On PC the player was to aim towards the cursor, and capping that to 45 degrees plays horribly. To solve this problem, our artists were forced to rebuild all animations in a different way. Since some of our characters still didn't have a clear waistline, the choice was made to make only the arms freely rotating. So on PC, the shooting arm always rotates towards the cursor.

Combining this with what we already had, turned out to look fantastic. There are a couple of reasons for this. First of all, our artists had drawn all characters somewhat from the side and with the shooting arm at the back. This means that the rotation point of the arm is always hidden behind the shoulders, thus nicely hiding the ugly rotation point of the arm. The other great thing is that the 45 degrees animations for the body combine well with this: while the arms rotate freely over 180 degrees, the body makes jumps every 45 degrees to follow that. This looks really slick, and makes sure that if the character is aiming upwards, he also looks upwards. This is really important for making it look convincing.

Our art team did have to add the missing directions, though. So now we needed 5 directions for each animation (5, not 8, because our characters still cannot aim backwards).

Aiming on PC is a combination of a freely rotating arm and the 45 degrees body animations from the console version.

Making all of these animations was an enormous amount of work, and part of the reason why Awesomenauts took so long to make. However, seeing the end result, I am incredibly proud of what we achieved, and I think our art team really did a tremendous job.

For the next blogpost, I would like to discuss an important related topic that wasn't covered today: shooting. How to combine shoot animations with a moving character that needs consistent leg movement? We used a couple of quite clever tricks for that (or so I like to think), so I will explain how shooting was made in my next blogpost. See you then!

Saturday, 18 August 2012

When we developed Awesomenauts for console, we had the benefit of working with a publisher that helped us with QA (Quality Assurance, also known as testing) and translations. However, on PC we have self-published Awesomenauts, and that means that we had to take care of these things ourselves. Being low on budget and time, we decided to take the more radical route: we crowdsourced large parts of both.

For those who don't know the term: crowdsourcing means asking the public to help you, outsourcing to the crowd. So we did a beta where people could play the game before launch, and tell us if they found any bugs. And we asked players to help us translate all the new texts to German, Italian, Spanish and French. Since crowdsourcing is such a hot topic these days, I figured it would be interesting to share our experience with the translations.

At first, I was quite reluctant about letting players do translations. Despite our budgetary problems a few months ago, I was in favour of paying a translation company to do it, thinking that would be faster, more reliable and better quality. However, my colleagues wanted to give crowdsourcing a try, and so we did. And know what? Crowdsourcing turned out great, way better than even the biggest optimist at Ronimo had expected!

To find translators, we opened up an email-address for players to sign up for translating to a specific language. We promoted this on our Facebook, Twitter and forum. Within a week, we got several dozen reactions, meaning we had enough translators to have backup if someone bailed out at the last moment. It was also enough to have them double-check each other's texts.

Since we had some new and (at the time) secret features (like the new character Gnaw that is coming this week), we asked each of the translators to sign a short NDA (Non-Disclosure Agreement). An NDA is a small contract that simply states that any secrets we share are to be kept secret. I generally dislike the formality of putting everything under contract, but for something like this it is nice to make it very clear to the testers that we really don't want any unreleased information to leak. For an indie studio, the most important marketing tool there is, is which information is revealed when. So keeping that under control is very important for us.

Once that was taken care of, we simply put our spreadsheet with texts on Google Docs and gave them access. From there, the magic happened... I was absolutely baffled to hear that the very next day, everything had already been translated. No commercial translation company we previously worked with ever worked that fast! And they took their job very seriously: in the following days, they checked each other's work (marking what had and what had not been checked), and extensively discussed how to translate some of the genre-specific words. They even made some improvements to the existing console translations!

Awesomenauts has been out for over two weeks now, and we have not heard any complaints about bad translations. So despite that I don't speak Italian and thus cannot check the Italian translations to see whether they are any good, I think I can conclude that the translators did a great job. Players are quick enough to complain about any other issues in the game, so if they didn't complain about this, then it must have been good enough! ^_^

Another benefit of how this turned out is that if we have any new texts, we can just send them to the translators and they usually have new translations for us within a day. Compared to the formal requests for new translations that we had to do to commercial translation companies in the past, and the time it took for those to come back in all languages (usually one to two weeks), crowdsourcing is just incredibly easy and fast!

Of course, we also wanted to give something back to our translators, so we gave all of them a free copy of the game on Steam. More importantly, we also gave them a special icon in the game: the Golden Duck! (This may sound silly, but I think it is important to officially honour people who help us, and what in the world is cooler than a Golden Duck?!?!)

This blogpost so far obviously suggests that crowdsourcing is a great idea. I think it is, and I wonder: wouldn't it be possible to take this a lot further? Why not let players design puzzles for a puzzle game, for example? Looking at how much user-generated-content has been made for games like Portal 2 and Little Big Planet, I think a lot of players would be honoured to contribute a couple of puzzles to a game! Why not ask users to design puzzles before release and include them in the game? In a sense, this might feel like abusing their time, so maybe some kind of compensation would have to be figured out for that. But then again, I think if they got a chance to contribute to a game they love, lots of players would feel honoured, not abused! Making games is one of the most fun jobs in the world, and quite a few gamers would love to be a bit closer to that by contributing to an actual game.

After all this jubilant talk about crowdsourcing, it is time to mention some of the downsides. For one, I think rallying players becomes a lot more difficult if you don't have an existing playerbase yet. Quite a few people already knew Ronimo from Swords & Soldiers and De Blob, and we already had a ton of Awesomenauts players on console. I guess for your first game, it is a lot more difficult to find enough translators who are willing to really help you.

Another problem is that on console, there are a lot of certification requirements. Console manufacturers think it is necessary to define whether a button is pressed or clicked, and if you use the wrong word, your game might fail certification. (This example is not made up, one of the current consoles actually has this exact requirement...!) Working with players is a risk for these kinds of requirements, since they might not know about them. Professional translators know all the certification rules (or at least, they should...).

There is also the risk of a malicious person putting in weird texts. This happened to Minecraft, where an official release contained a racial slur in the translation to Afrikaans. Having translators double-check each other's work helps against this, but it is always a risk that someone changes a text at the last minute and this kind of horror ends up in an official release...

Despite these potential downsides, crowdsourcing has so many benefits, that I feel it is a great idea. It turned out that it is not just cheap for the developer, but also incredibly fast and a fun way to interact with the community and have them add something of their own to the game.

To conclude, we would like to thank our community translators for their great help and support!

Saturday, 11 August 2012

Joysticks on PC are absolutely insane. Not only are there all kinds of joysticks, but the creators of joysticks and joystick libraries have added some ridiculous inconsistencies and omissions, making supporting them a lot more hassle than it could have been if sensible people had made these. This is quite common knowledge among developers, of course, but while adding proper joystick support to Awesomenauts for the PC version, I learned that it was even worse than I thought. So for anyone who wants to have a very sour laugh, or considers supporting joysticks in his own game, here is a list of the oddities I have encountered.

Note that when I say joysticks, I actually mean all kinds of controllers, so also steering wheels, big force feedback flight simulator joysticks and of course the kind of controllers used on the Xbox and Playstation.

Joysticks have different layouts

This one is rather obvious, because you can actually see this when you look at a joystick: they all look different and the number of buttons and sticks they have can vary wildly. This makes perfect sense, since a flight sim has radically different requirements than a racing game. However, this does make adding proper joystick support on PC always a lot of work, because many joysticks simply don't work if you lack a very complete controls configuration screen.

It gets even more complex because some sticks don't even have a neutral position, like the throttle on a flightsim joystick. Such sticks can remain in full-output all the time, which is an added complexity when detecting what axis or button the user is trying to assign to an action.

Similar joysticks have randomly different mappings

This is where the craziness starts: joysticks that have exactly the same buttons and sticks often output those under randomly different numbers. It seems rather trivial for joystick manufacturers to come together and all agree on the same indices here, since these numbers don't have any impact on the actual features of the controller. Yet somehow they are so incredibly lame that they have never done this, and all have randomly different numbers for the exact same features.

Common libraries OIS and SDL don't support dynamically connecting

This is rather surprising to me. On console, when the user disconnects his controller he gets a nice warning message, asking him to reconnect. Since this makes a lot of sense, I wanted to do the same on PC. However, it turns out that OIS and SDL, two of the libraries that are used often for multi-platform joystick support, both don't support dynamically connecting and disconnecting controllers. Joysticks only work when they were already connected before the game started, and it is impossible to detect whether a joystick was disconnected.

The lack of this feature is extra surprising when you know how simple this is to implement: both DirectInput and XInput report whether the joystick is still connected when you try to find out which buttons are being pressed. However, somehow SDL and OIS both choose not to expose this information to the user. Meh. Note that SDL does plan to add this in the future in version 2.0 (whenever that comes), but SDL has existed for 14 years already and this seems rather late for such a basic feature.

An extra reason why this is so annoying, is that wireless controllers may report that they are not connected until you press a button. So if you don't press that button before the game starts, then the joystick won't work until you restart the game.

This is the main reason why I chose to remove our SDL and OIS joystick implementations and have instead built my own joystick library with the more low-level DirectInput and XInput libraries.

Drivers for the 360 controller on PC are insane

For low-level joystick support on Windows, the best libraries to use are DirectInput and XInput, both by Microsoft. Strangely, there is a battle between XInput and DirectInput, and the choices Microsoft made here are just straight out unbelievable...

The documentation of these libraries suggests that that DirectInput is the old standard, and XInput is the new one. However, this is not the case: XInput only supports the Xbox 360 controller. It does explain that all controllers that don't support XInput are 'legacy' controllers, but XInput is completely inflexible in terms of number of buttons and such. There are some joysticks that support XInput, but they always have to have the exact same layout as an Xbox 360 controller. This means that according to Microsoft, any new flightstick is automatically 'legacy'. I just can't do anything but cry when I see this piece of documentation...

DirectInput on the other hand documents that it is a flexible library that is set up to support every kind of joystick layout. It does not mention, however, that Microsoft's own Xbox 360 controller is one of the few (only?) joysticks that is not properly supported. Here's a little summary of the oddities regarding the Xbox 360 controller:

In DirectInput, the Xbox 360 controller does not support rumble.

In DirectInput, the two triggers on the shoulders are mapped to a single axis, so it is impossible to detect pressing both at the same time.

Voice chat through a headset connected to a 360 controller only works through XInput.

Since the Xbox 360 controller is, as far as I know, by far the most popular joystick for PC gamers, this means that for good joystick support, it is pretty much necessary to always implement both DirectInput and XInput. Lame!

XInput performance lameness

An extra 'nicety' of XInput that I came across is that you are supposed to check whether the controller is connected by calling XInputGetState for all four controllers. However, if you do this while they are not connected, then this will cost a lot of performance. I measured this on various PCs and the time it takes to call XInputGetState for four disconnected controllers was 2ms to 10ms (!). On 60fps a single frame can only take 16ms, so 10ms for checking whether 360 controllers are connected is a lot! The solution was to use windows events to learn whether a new Xbox 360 controller might have been connected. It is incredibly lame that XInput itself does not have an efficient way to detect connecting a controller, and it is even lamer how the XInput documentation advertises a method that actually takes a lot of performance if there is no Xbox 360 controller!

Some joysticks have a "mode" button

This is a pretty neat feature of some joysticks: to work with games that don't support all kinds of controllers, some joysticks feature a "Mode" button that may do things like making the DPAD act like a stick. On controllers that only have a DPAD and don't have a stick, this is a great feature to support more games. However, if you are programming for such a joystick and don't know this, and accidentally hit the Mode button, then this is a good excuse to get completely confused. An especially nice example of this is the Speedlink PS3 controller:

Some joysticks have buttons that act as several outputs

This is also a good thing to know and take into account when programming joystick support for a game: when pressing a single button on some joysticks, it outputs as if you are pressing two different buttons. For example, on one specific USB Super Nintendo controller the DPAD outputs both as buttons 1 to 4, and as a stick. Interestingly, the DPAD does not output as a DPAD.

Many of the things mentioned in this blogpost are not useful in any way. They are just the result of incredibly bad design. Not all, of course, but especially the random button mappings and the inconsistencies between DirectInput and XInput are just so stupid and lame...! So, if you ever plan on making a PC game with joystick support, be sure to take these awesome 'features' into account, and plan some serious time to get it right! (Or just waive it, like many developers seem to do, and don't really support joysticks properly. Sure saves a lot of time!)