Friday, March 25, 2011

Before and after screenshots

I haven't written anything recently, as I was busy porting Jigsaw Guru Free to Android. I have a lot to say about this experience, but before that, here is another post I've wanted to share for quite a while: the "before and after screenshots" comparison.

I suppose this is not something developers show very often, but I think it can be interesting to see how a game evolves during its development, and what a difference real content, as opposed to placeholders, can make (this article only talks about graphics, but this is the same for music and sound effects).

Some people have multiple talents, and can create the different elements required in a game (design, code, art, sound...) on their own. I'm not one of them, I was born a programmer, and all the art I can make is coder art with underappreciated colors. As soon as I started working on Jigsaw Guru, I knew I would contract somebody to make my game look prettier (which means I didn't even try to make my best coder art ever ;)), let's see the result.


Title screen

before

after

This is the title screen and main menu. The old background (top) was generated programmatically, by separating and randomly rotating the pieces of a completed puzzle, and using a different photo for each of them. At this stage of development, "best times", "credits", and "settings" were simply not implemented yet. "Support" was reusing the Help icon, since I didn't know what to draw. The round buttons (bottom) with little blanks and tabs making them look like puzzle pieces were the artist's idea.


Picture selection

before

after

This is the first rotating menu the player sees in the game. Having a background was always part of the plan, but the black border was not; this forced me to push everything (buttons, texts, photos) a little bit away from the sides of the screen, and you may notice the photos are a bit smaller. Lesson learned: don't put your UI elements too close to the borders of the screen, even if the platform you're working on doesn't have a "title safe area" like the Xbox360.


Puzzle screen

before
 
after
 
On the puzzle screen, I used a checkerboard pattern for the longest time as the background, and also in the piece browser on the left. Initially, this was because it wasn't easy to see the shape of dark pieces on a black background, or the shape of bright pieces on a white background, you get the idea. After a while, I added an outline to the pieces to solve this issue, but somehow the checkerboard remained, until only a few days before submission. You can also notice the 4 buttons are in a different place, when the photo is horizontal like here they move to the bottom of the screen so that they don't hide the picture.
 
 
Pause screen

before

after

I still kind of like the way the old version looked: even if the image was a bit stretched (from a 4/3 to a 5/3 ratio), it was nice to see it in full screen. But depending on the colors of the photo, the round buttons, and the texts under them, were not always very readable, and the old layout didn't work well with vertical pictures. And since the photo is smaller, I got some extra space to add tips, and encourage players to discover more features (such as the helps: I was under the impression nobody wanted to open that menu, maybe people feel like they failed if they use helps? Personally, I use them all the time!)


Helps

before

after
 
 Speaking of the devil... This is another rotating menu, that combined the problem of the photo selection one (UI had to be moved to make room for the border) with the checkerboard pattern of the puzzle screen.


Overwrite confirmation

before

after
 
This is an example of a false good idea: you're on the pause screen, you hit the save button to save the current game, and instead of replacing the pause screen, this confirmation shows up on top of it (if you didn't see it, look carefully at the 'before' screenshot: you can see the full screen photo, and the 'save game' and 'help' buttons, 'behind' the current screen). In the best case scenario, this doesn't make much difference, in the worst case, it's confusing and less readable (not to mention: inconsistent with the rest of the application).


That's all folks

Hopefully this post convinced you presentation is important, and there's nothing wrong with working with other individuals who are more talented than you, while you focus on the things you like and do best. Also, when you program menus and other non-gameplay screens, try not to use a black uniform background: once you replace it with something else, you might discover some UI elements or texts don't work well with the new colors or patterns, and you'll have to spend some extra time to fix them. Believe me, I've been there.

Monday, February 7, 2011

Free is good

At the end of the postmortem I wrote for my Windows Phone 7 game Jigsaw Guru, I mentioned I was about to submit a free, ad supported version of the application, since the downloads and sales of the paid game were extremely low. When Jigsaw Guru Free was released on December 29, I said I would write another post after a few weeks, and share some results. This is the post you are reading, I now have all the data related to the first month (12/29/2010-01/28/2011) of Jigsaw Guru Free on the marketplace, so let's get started.


Downloads


This should speak for itself:

Figure 1: downloads for Jigsaw Guru (10/23-01/28)

Figure 2: downloads for Jigsaw Guru Free (12/29-01/28)

The paid version got 103 downloads in over 3 months, the free one got 13 109 in its first month. That's 127 times more, in a shorter period of time. And if you look carefully at the first figure, you will notice the download rate for Jigsaw Guru increased a bit before the beginning of the year: that is because of the free version, even if it doesn't contain any information or link to the paid game (which was a mistake on my part), some people searched for and found the initial product after seeing the new one.

I don't want to state the obvious, but this shows your game has a much bigger chance to find its audience if it's free, and if it's not you probably should make a light but free version of it to let people know about your paid application. This is the same principle as on the iPhone, and as I mentioned in the postmortem, the trial mode implemented by a lot of Windows Phone 7 games (including mine) is not a good substitute for a free version, that system as it is right now unfortunately doesn't work (because it doesn't give your game any exposure outside of the section for paid apps, which has much less traffic).


Ad impressions


Of course it's good if a lot of people download your game, but if they try it once and uninstall it immediately, or never play it again, then what's the point? I don't have any analytics system built into Jigsaw Guru Free, to keep track of the number of active players, and sessions, and a bunch of other things, but  I have ad impressions. That basically tells me how many ads were displayed by the game every hour, I just can't see if it's a small number of people playing for the whole hour, or a lot more players only spending a few minutes in the program.

What's interesting is the number of ad impressions has been very stable for me so far. Of course it goes up a bit during the week end (people have more free time), and down in the middle of the week, but the changes are not drastic. Jigsaw Guru Free started just under  9000 impressions per day, is now doing between 16k and 17k most of the time, and served close to 420k ads in its first month.


eCPM


The eCPM (effective cost per thousand - shouldn't that be eCPT?) is basically how much money you get for 1000 ad impressions, so, that's a very important number. Unfortunately, unlike the impressions themselves, it can vary a lot from one hour to the next (or at least that's what I saw in January). Which makes it difficult, if not impossible, to predict how much ad revenue you're going to get the next day, since revenue = impressions / 1000 * eCPM.

Many factors have an influence on eCPM, I only know a few of them, and some are out of our control: for example, if a lot of advertisers are running big campaigns at the same time, eCPM will go up, since there is more demand for ad space; on the opposite, if it's a more quiet period, eCPM goes down, like it did in January. As developers, the main parameters we have access to with the Microsoft ad SDK and the corresponding pubCenter website are ad categories, application keywords, and phone location.

When you create an ad unit, you can select up to 3 categories of ads you want to receive. These can be really large categories such as "Sports", or more targeted subcategories like "Sports - Skiing". This selection seems to be the most important step in getting a good eCPM, but there is no list of what the 3 best categories are, and if there was one it could change over time anyway. The good thing is: categories are not hard coded in the application, they are defined on pubCenter, which means you can change them at any time without submitting an update, and the new categories are used instantly or in the next hour as far as I can tell (I changed mine one time in the middle of January). You can experiment as much as you want, maybe changing one category at a time, but don't forget that many other factors affect eCPM, and you're not necessarily always comparing apples with apples. 

I have one piece of advice though: don't choose categories based on what your application or game does. That's what I initially did, because that sounds like a good idea to have a better click-through rate (CTR, percentage of ads being clicked / tapped when they are displayed), and for example one of my categories was "Travel", since the photos provided in Jigsaw Guru Free all show places you may want to visit while you're on vacation. I'm not saying Travel is a bad category, or Astronomy is a bad category (someone in the forums mentioned he was using that one), but how often do you see advertisement about travel and astronomy, compared to some other products? So, my advice is to just look at commercials you see a lot on TV or in magazines, and pick the categories they would fall into: if companies making these products spend a lot of money advertising them in other media, there's a good chance they (or their competitors) will do the same on mobile phones. CTR may be one of the factors secretly influencing eCPM, but even if it does, categories have so much weight right now that it makes more sense to focus on them first.

Application keywords can be specified in your code, which means you cannot change them without submitting an update. This is not a problem for now: they're not taken into account by the current version of the Microsoft ad SDK anyway (this could obviously change in a future release).

Finally, your program can provide the phone's location to the ad manager (XNA) or control (Silverlight), and this can increase your eCPM if some campaigns are specifically targeting the area where the user is when he's playing your game. I have no idea how much of a difference this can make, but it cannot hurt. Just be careful and re-read the certification requirements if you implement this: you need to ask customers if they want to allow your app to use the location or not, and they should be able to opt out at any time.


Ad revenue


How much money did I make in one month with Jigsaw Guru Free? I won't give the exact amount, but here is what I can say:

  • much more than I did with the paid Jigsaw Guru. Especially since the latter is still very far from reaching the payout threshold, and I may very well never see a check for it.
  • with about 2 million phones in circulation right now, and 13k downloads of my only game on the WP7 so far, the ad revenue doesn't pay all my bills. This is to be expected, let's be realistic, I'm not disappointed at all.
  • on the contrary, the good news is what I made in January will pay for my rent in Southern California, in March (since I should get that money at the end of February). This is a pretty good start, and with a couple more projects on the market, or some ports of the same game to other platforms, I could eventually be able to balance my budget in a few months if everything goes well. It's certainly not a done deal though, this will depend a lot on how eCPM evolves in the future, how successful my next game is, etc. But there is hope :-)


Free is good


Making a game available for free has a couple more advantages I want to mention. The first one is related to piracy: since the game is free, I don't have to worry about people eventually managing to install and play it without buying it, actually the more people have it the happier I am.

The second one has to do with Android: I don't know how that happened, but apparently customers on that platform are used to getting everything for free, to the point that it's now an expectation, and even Angry Birds was released as a free ad supported game. I find it kind of sad that people are not willing to spend a few dollars on a high quality product (after all, the persons who developed it need to earn a living, don't they?), but at least if I ever want to port something to Android I won't have a problem with the $0 price tag, since that's the one I would choose anyway.

Free is good. My next game will definitely follow that path, the only question is whether I will also have a paid version with some extra features and without ads, or not.

Sunday, January 30, 2011

The main differences when porting a game from Windows Phone 7 to Xbox360

Since the Xbox360 version of my game Jigsaw Guru was released on the marketplace a week ago, I thought I could write a post about the main changes I had to make to go from a mobile device to a living room console. Those changes basically fall under 3 categories: screen, input, and storage.


Screen


A TV screen is obviously bigger than the screen of a phone, but more importantly it has a different resolution and aspect ratio. The difference can actually be huge, if the game runs in portrait mode on the phone:

Jigsaw Guru on Xbox360, 1280*720
Jigsaw Guru Free on WP7, 480*800

Fortunately for me, the initial paid version of Jigsaw Guru runs in landscape mode on the phone, but going from 800*480 to 1280*720 still means all the graphics elements have to be scaled and positioned according to the width and height of the screen, which I do with code looking like this:

successRect.X = (int)(Renderer.Instance.DeviceWidth * 0.1f);
successRect.Width = (int)(Renderer.Instance.DeviceWidth * 0.8f);
successRect.Y = (int)(Renderer.Instance.DeviceHeight * 0.4f);
successRect.Height = (int)(successRect.Width * completedText.Height / completedText.Width);
spriteBatch.Draw(completedText, successRect, Color.White);

These lines are used to display the "Puzzle Completed" texture; successRect is an XNA Rectangle, Renderer.Instance is a singleton I use for all my rendering code, and as you can see all the dimensions I need are expressed as a percentage of the width or height of the screen. This is a pretty convenient system, for example tweaking the value returned by the DeviceHeight property was enough to make room at the bottom of the screen for the ad banner of the free version, and force the game to only use the top 90%. This won't solve every single case though, sometimes scaling the UI is not enough and a different layout needs to be used; but even if you're only working on 1 platform, it's better to not hardcode your sizes and positions in pixels, in case you want to change the resolution or support several aspect ratios (such as 4/3 versus widescreen) later on.

Televisions have a very annoying property: they don't display the whole image your console sends them. Depending on the model, up to 10% of the screen can be missing on each side, and you should therefore only draw important information in the remaining 80% zone in the middle, which is known as the "title safe area" (this is a certification requirement, if you don't follow it your game will not be approved on Xbox360). This actually took a big portion of the time I spent porting Jigsaw Guru to the console: I couldn't use the previous trick to make the game fit in the title safe area, because 1) you don't want to have a big black border on televisions that can display the whole image or most of it, 2) you don't want to only use 80% of a phone screen that's small enough already.

For this particular problem, I still tried to avoid having too much platform specific code everywhere I draw text and icons, by using a mix of small functions and constants like the following ones:

#if XBOX
        public const float textTop = 0.10f;
        public const float textBottom = 0.90f;
#else
        public const float textTop = 0.07f;
        public const float textBottom = 0.93f;
#endif

For example, the "Select Game to Load" title in the previous screenshots is positioned like this:

textPosition.Y = Renderer.Instance.DeviceHeight * textTop;

instead of directly using DeviceHeight * 0.07f like I could do it if I was only developing for the phone. This makes sure the text is low enough to be entirely contained in the title safe area on the Xbox360. Also, to verify everything is correct on all the screens, I have a boolean I can toggle in debug mode to draw the title safe area limit as a red line:



Input


Playing with a gamepad is of course totally different than playing with a touch screen, no surprise here. Therefore, the main input related change in the Xbox360 game is that the player moves a cursor on the screen to drag and drop puzzle pieces, instead of moving her finger. Also, some icons became unnecessary: for example, you don't tap a pause icon to go to the pause menu, you just press the Start button on the gamepad. But the modifications don't stop here.

The console can have up to 4 controllers connected to it, and a player must be able to pick any of them to play. That's why every Xbox360 game has a "start screen" before its main menu, where the controller used to press Start is detected, and remembered for the rest of the session (changing controller mid-game doesn't have to be supported, it's not a requirement).



In menus, you have to keep track of a "currently selected" item: on the phone, any icon can be tapped at any time, but on the console the player can only navigate to the previous or next item one step at a time.

Finally, games usually have a "controls screen" like the following one, and I didn't have anything like it on the WP7:



Storage


Saving settings and games to isolated storage and reloading them is fairly easy on WP7. On Xbox360 however, this is a different story: players may or may not have memory units, if they do they need to be able to select which storage device (including the hard drive) they want to use, and the game should never crash even if the selected device is removed at any time (while playing, loading, saving, you name it). In my opinion, this is the most annoying requirement to fulfill, it's not particularly difficult to implement it, but it's hard to think about all the different cases and places where something might go wrong and test them. Here are two things you can do to make your life easier, and hopefully avoid failing during peer review.

Use the EasyStorage library. Lots of Xbox Live Indie Games developers do it, and that's what I did too, even if I wouldn't have needed it for the WP7 version. I don't use the asynchronous functions because the files I read and write are very small and don't require any kind of progress bar, but I know they're here in case I want them in a future project.

Protect all your file accesses with try/catch blocks. Even checking if a file exists can fail if the storage device was removed, so don't be shy, and better be safe than sorry. Try to give some feedback to the players if you can, so that they don't assume their game was saved if it wasn't, they would hate you for that the next time they play (I know I would).


The other way around


What about going the other way around, and porting an Xbox360 game to the WP7 platform? Well, I haven't done that so I don't have much experience with it, but from the top of my head there are two phone specific things you'll have to pay attention to, in addition to what I have mentioned in this article: tombstoning, and the use of the Back button. Those are actually 2 of the main reasons for failing submission on the WP7, even when you're writing a game directly for that platform, so don't wait until the last minute to take care of them, the earlier you know what modifications they will require in your project the better.

Monday, January 17, 2011

Parallel.For: easy multithreading in C#

Quest for speed


Last December, I experimented for a while with SPH (Smoothed Particle Hydrodynamics), using C# and XNA as usual. Of course, the more particles you can simulate the better, and I tried to optimize  for speed the different parts of the method as much as possible, which even led me to use a SOA (Structure of Arrays) rather than the more natural AOS (Array of Structures) for my data, since I basically ended up being limited by the speed of memory accesses and cache misses. Anyway, I thought I had done my best and I had no plans to multithread this code, when I ran into an explanation of Parallel.For and Parallel.ForEach on the internet, and decided to give it a try.


The original code


Let's start with a simple function:

        private void MoveParticlesSOA(float deltaTime)
        {
            Vector2[] positions = particleSystemSOA.Position;
            Vector2[] forces = particleSystemSOA.Force;
            float xMax = dimensions.X;
            float yMax = dimensions.Y;

            for (int p = 0; p < particleSystemSOA.NbParticles; p++)
            {
                Vector2 position = positions[p];

                if (position.X < 0)
                    position.X = dimensionEpsilon;
                else if (position.X > xMax)
                    position.X = xMax - dimensionEpsilon;

                if (position.Y < 0)
                    position.Y = dimensionEpsilon;
                else if (position.Y > yMax)
                    position.Y = yMax - dimensionEpsilon;

                positions[p] = position;
                particleSystemSOA.UpdateParticle(p, deltaTime);
                forces[p] = Vector2.Zero;
            }
        }

What this code does is for each particle, it first makes sure the position is inside a 2D rectangle (these are the if/else lines),  then it asks the particle system to move the particle, and finally it resets the forces applied to the particle to zero (for the next frame). Since there are potentially a lot of particles to deal with, how would we go about multithreading this function, so that it can take advantage of 2, 4, or more cores?


Parallel.For


This is what it looks like with Parallel.For, after I added some #if/#else/#endif statements to easily enable or disable multithreading:

        private void MoveParticlesSOA(float deltaTime)
        {
            Vector2[] positions = particleSystemSOA.Position;
            Vector2[] forces = particleSystemSOA.Force;
            float xMax = dimensions.X;
            float yMax = dimensions.Y;

#if PARALLEL
            Parallel.For(0, particleSystemSOA.NbParticles, p =>
#else
            for (int p = 0; p < particleSystemSOA.NbParticles; p++)
#endif
            {
                Vector2 position = positions[p];

                if (position.X < 0)
                    position.X = dimensionEpsilon;
                else if (position.X > xMax)
                    position.X = xMax - dimensionEpsilon;

                if (position.Y < 0)
                    position.Y = dimensionEpsilon;
                else if (position.Y > yMax)
                    position.Y = yMax - dimensionEpsilon;

                positions[p] = position;
                particleSystemSOA.UpdateParticle(p, deltaTime);
                forces[p] = Vector2.Zero;
            }
#if PARALLEL
            );
#endif
        }

Simple, isn't it? The 'for' line is replaced with Parallel.For, and what used to be the loop's code is now a delegate that can be called on several threads simultaneously for different particles. All the synchronization is taken care of automatically, it's pretty awesome if you ask me!


Shared memory


Parallel.For and the other methods of the Task Parallel Library don't do anything special regarding shared memory, and it's the programmer's job to protect the latter from data races and simultaneous accesses from different threads. Let's see another function from my SPH class as an example (sorry it's a bit long, there's no need to read it line by line as I will explain the important parts right after the code):

        private void UpdateDensityAndPressureSOA()
        {
            Vector2[] positions = particleSystemSOA.Position;
            float[] densities = particleSystemSOA.Density;
            float[] pressures = particleSystemSOA.Pressure;
            short[] gridIndex = particleSystemSOA.GridIndex;

            for (int p = 0; p < particleSystemSOA.NbParticles; p++)
            {
                densities[p] = 0f;
                neighborCount[p] = 0;
            }

#if PARALLEL
            ParallelOptions options = new ParallelOptions();
            options.MaxDegreeOfParallelism = -1;
            Parallel.For(0, particleSystemSOA.NbParticles, options, p =>
#else
            for (int p = 0; p < particleSystemSOA.NbParticles; p++)
#endif
            {
                int nbNeighbors;
                int[] neighbors = grid.GetNeighbors(particleSystemSOA, gridIndex[p], out nbNeighbors);  // NOT GOOD FOR MULTITHREADING

                for (int n = 0; n < nbNeighbors; n++)
                {
                    int neighborIndex = neighbors[n];
                    if (neighborIndex < p)
                        continue;

                    if (neighborIndex == p)
                    {
                        densities[p] += selfDensity;
                        continue;
                    }

                    float deltaX = positions[p].X - positions[neighborIndex].X;
                    float deltaY = positions[p].Y - positions[neighborIndex].Y;
                    float r2 = deltaX * deltaX + deltaY * deltaY;

                    if (r2 < h2)
                    {
                        float diff2 = h2 - r2;
                        float density = poly6FactorMass * diff2 * diff2 * diff2;
                        densities[p] += density;
                        densities[neighborIndex] += density;

                        float r = (float)Math.Sqrt(r2);

                        if (neighborCount[p] < maxNeighbors)
                        {
                            int tableIndex = p * maxNeighbors + neighborCount[p];
                            neighborTable[tableIndex] = (short)neighborIndex;
                            neighborDist[tableIndex] = r;
                            neighborCount[p]++;
                        }

                        if (neighborCount[neighborIndex] < maxNeighbors)
                        {
                            int tableIndex = neighborIndex * maxNeighbors + neighborCount[neighborIndex];
                            neighborTable[tableIndex] = (short)p;
                            neighborDist[tableIndex] = r;
                            neighborCount[neighborIndex]++;
                        }
                    }
                }

                const float restDensity = 100f;
                const float gasConstant = 0.1f;

                pressures[p] = gasConstant * (densities[p] - restDensity);
            }
#if PARALLEL
            );
#endif
        }

I won't go into the details of this function since they're not relevant to the current discussion, as the name indicates it basically calculates the density and pressure of the fluid at each particle's position. But there are two interesting things we haven't seen yet that I want to discuss.

The first one is just after the first #if PARALLEL line: as you can see, options can be passed to Parallel.For, such as the maximum number of threads you want to be used. Here I specified -1, which is the default and means all the available cores will be used, but you could pass 2, 4, etc.

The second topic I need to talk about is the line with the NOT GOOD FOR MULTITHREADING comment. This line in itself has no problem, but it calls a function of a grid that's used to find the neighbors of a particle (that is, other particles that are within a given radius of the current one) without having to test all the particles each time. Since a particle usually has a bunch of neighbors, the GetNeighbors function would initially store their indices in an array that was part of the grid object, and return a reference to that array. Once this function can potentially be called by several threads at the same time, this approach doesn't work anymore: the threads all try to access the same piece of memory simultaneously, and you can trust me when I tell you the SPH simulation became totally unstable as a result.

How do we fix that? Well, since I was only trying Parallel.For for the sake of trying it, I did the simplest thing I could think of just to verify that would fix the simulation and there wasn't any other problem: GetNeighbors allocates and returns a new array each time it is called, which means each thread gets its own piece of memory, each time it calls the function (that's the annoying thing, since one thread could totally reuse the same array for all the particles it handles). That's a lot of allocations per frame, that sounds crazy, and I don't recommend doing it in real code, although we're going to see in the next section that it wasn't so bad after all.


Performance


So far we've seen that Parallel.For is very easy to use, definitely much much easier than managing a bunch of threads manually, managing a bunch of BackgroundWorker objects, or using the ThreadPool class (even if I haven't shown these methods in action, and I'm not saying they  don't have some valid usage cases). But what about performance?

Unfortunately, I don't have numbers to give you, since like I mentioned before, my algorithm was already memory bound when running on one core, and processing power was not the issue. But let me say this: despite the memory bottleneck, and all the extra allocations made in the GetNeighbors function, the multithreaded version of my SPH simulation still managed to run faster than the non-multithreaded one, which is a great sign in my opinion. And eventually also shows allocating memory is crazy fast in C#, and the garbage collector does a good job at quickly getting rid of short lived objects, at least on PC.

I really encourage you to read a bit more documentation about the Task Parallel Library, and try it for yourself on some existing code that could use more multithreading, I think you'll be happily surprised.

Wednesday, December 29, 2010

Jigsaw Guru Free released today

The free, ad supported version of my Windows Phone 7 game Jigsaw Guru was approved today, and is ready to be downloaded from the marketplace. It's basically the same game, with no limitation (meaning: you can use any picture from your phone as a jigsaw puzzle, in addition to those provided in the application), and it's free. But there are actually a few more differences between the two versions:

  • The most obvious one is that Jigsaw Guru is a lanscape mode game, whereas Jigsaw Guru Free is in portrait mode. I made this change for two reasons: first, the Microsoft ad SDK only serves horizontal banners for now, which were clearly designed for portrait mode applications and are easier to fit in the screen that way. Second, the submission process and the Zune software only support vertical screenshots, which makes it less convenient to look at landscape mode games in the catalog. Reorganizing all the screens took a bit of work, but I think it was worth it.
  • I added tips to the pause screen. They rotate automatically, but can also be glanced through by tapping them.
  • The piece browser displays 8 pieces instead of 6.
  • I removed one of the icons from the puzzle screen, since none of my testers was using it, they couldn't remember what it was for, and I had a hard time explaining it.

I'm curious to see how many people will download Jigsaw Guru Free, and I'll try to write a post with some numbers in a few weeks. If you've read the game's postmortem, you already know it can only get better :)


Wednesday, December 22, 2010

Jigsaw Guru for the Windows Phone 7 postmortem

New beginning

When my job position got terminated last summer, I decided I would take a break from working for big companies, and try to make a game on my own at home. I've been in the video game industry since the late nineties, I've written code for a few released PC and console AAA titles and probably as many canceled ones, and I wanted to do something different at least for a few months. Go back to the roots of game development, when one or two guys could create something in their garage or bedroom, without spending years and millions of dollars on it.


Platform choice

I'm a C# fan, I won't deny it, I even explained why back in 2007. I also toyed with XNA each time a new version was released, and I like how straightforward it is to use. When the beta version of the tools to develop for the Windows Phone 7 (WP7 for short) became available, just at the right time for me, it seemed like the obvious choice for what I wanted to do. And developing for a brand new platform sounded exciting as well, even if it was perhaps a riskier bet than targeting well established markets.

For those who don't know much about WP7 development, I just want to highlight a few key points:
  • Applications are written in Visual Studio using C#, and either XNA or Silverlight. This may come in the future, but at this point you are not allowed to mix them, and use the controls of Silverlight with the faster rendering of XNA, for example.
  •  In App Purchases are not supported yet.
  • Programmable shaders are not available for WP7 (they obviously are for the PC and XBox360) in the current version of XNA. Instead, you have 5 predefined shaders with features that can be toggled on and off (such as fog or per pixel lighting). These shaders should cover most of the usual needs, but if you want something very specific that they don't support, you're out of luck (or have to fall back to multiple passes and alpha blending).
  • Paid applications have a trial mode, that allows users to evaluate them before making a purchase. Unlike on XBox Live Indie Games (XBLIG), where the game just abruptly stops after 8 minutes, developers have a complete control over what they want to show in trial mode (for example, the first few levels of a game, with no time limit, or without the ability to save, etc). In theory, this means you shouldn't have to make a free version of your game in addition to the paid one, but I'll come back to this later.
  • The certification requirement document is only 27 pages long, table of content and change history included.


The project

I wrote a few ideas on paper, but they all looked too ambitious for a first project. One thing in particular that I wanted to avoid was to require a lot of content, since I didn't even know how I was going to find an artist yet. During a bike ride, I thought about using photos, and that's how I decided to make a jigsaw puzzle game. Not super original, I know, there are several of those on the iPhone and iPad, but there was none on the WP7 since it wasn't released yet :), and it looked like a good project of the right scope to keep things under control and learn the platform. For example, I had never worked with a touch screen device, and it was pretty obvious from the start that I was going to spend quite some time iterating on the user interface part of the game.


The game is called Jigsaw Guru, and you can find more screenshots and a video at http://www.fairyengine.com/.


What went right

I actually already mentioned some of the things that went right in my opinion, but here is the full list:

  • Working on a short project, without too much content to integrate, instead of picking another more ambitious and time consuming idea, was the right choice. My goal was to have Jigsaw Guru on the marketplace the day of the WP7 launch, I submitted it on 10/18 and it got approved on 10/23 (the update I submitted in December passed even faster than that), two weeks before the US launch and two days after the other territories started getting their phones. At times I still had more items on my to-do list than I would have liked, and I made a good push in the last 3 weeks to get everything wrapped up in time, but it never got too crazy.
  • Knowing the tools beforehand, and using C# and XNA, definitely made me feel productive. The phone emulator was surprisingly stable in the beta, and the XNA forums were very helpful when I wasn't sure about something. It's also worth noting that the website used to submit bug reports allows everybody to see what other people have written, and vote on issues you think are important and should be fixed first.
  • Garbage collection is the one thing that can hurt your framerate really bad when using XNA on XBox360 and WP7. But it's not that hard to avoid: when I had a look at my memory usage late in the project, I only found two spots where I was creating some amount of garbage each frame (both related to strings). Basically what I do is each time the player goes from one screen to another, I load everything I need for the new screen, and I force a garbage collection. This gets rid of temporary objects that may have been created during the loading process, and objects from the previous screen that are not used anymore. After that, I don't allocate anything, and the garbage collector never has to do any work.
  • Finally: testing. Very few people tested my game while I was developing it, but my friend Alexis alone kept giving me more feedback than I thought I could handle. He never said anything was good just to make me happy, he reported every little detail he didn't like, even and especially the ones I was aware of but never had time to fix (and maybe thought nobody would notice). Even if I sometimes felt he was nitpicking, this was exactly what I needed.


What went wrong

Developing for a new platform has its share of drawbacks, it's just how it is. The final version of XNA 4.0 only came out mid-September, and before that I was working with the beta version. As mentioned before, it was pretty solid already, but there was no redistribution of the runtime. Which means you had to install all the tools to be able to just run the game, and you could only install them under Vista or Windows 7 because the phone emulator requires DirectX10, and some of my potential testers were still using Windows XP. So, even if what I was sending was a PC version of the game, they couldn't run it on XP just because the phone emulator, which they didn't need, requires a more recent operating system. To work around this problem, I made an XNA 3.1 PC version of Jigsaw Guru, but maintaining two versions side by side for several weeks and merging back and forth between them was not fun.

Coding for a device that wasn't released yet also meant I could not test what I was doing on real hardware. I unsuccessfully tried to get a phone prototype, and basically the only way I found to run my game on a WP7 at the end of September was to go to a Microsoft event. Even there, I thought there would be phones locked to the tables, that developers could connect to their laptop and use for the whole day, but I was wrong: there was no such thing, and the 4-5 persons who already had a working application to test like me had to do it on the phone of the event's organizer, when he wasn't using it for something else. I was able to run my application twice for about 5 minutes each time, and fortunately everything seemed to be working fine, which is a testament of the reliability of the emulator.

When the game began to be really playable, with most of the screens that are in the final version, I started looking for an artist and a musician. I did it way too late, and I was lucky to find Aimee and Tim through the XNA forums, and that the time estimates they gave me just matched my own programming deadline. So, in the end everything worked out well, but even if I wanted to wait and be sure the UI elements were final before asking somebody to redo them, I believe I also waited just because I was more comfortable doing my programming tasks first, and that was a mistake.

Marketing was a difficult problem: I knew I needed to do some, but how? When Jigsaw Guru got approved, the WP7 wasn't out yet in the US, and had just been released in a few countries of Europe and Asia, as well as Australia and New Zealand. Basically, nobody had that phone yet, and I couldn't find any website reviewing its games. Even when I had a second look for the US launch, I only saw a couple of sites testing 2 or 3 of the official XBox Live games (that's how they're called even if they run on a phone), but nothing related to indie games. So, what ended up happening is I did nothing, and just hoped that because there weren't too many applications on the marketplace yet (which is the reason for being a launch title, right?), people interested in jigsaw puzzle games would fine mine. Of course I was wrong, and the fact that the search in the Zune software didn't seem to care about the keywords you enter when submitting your app, or couldn't find my game when searching for 'jigsaw', didn't help (this seems to be fixed now). I don't know how other developers releasing WP7 games around the same time as me handled their marketing, but I would be curious to hear it, that question is still a mystery to me. 


Downloads and sales

This could have been another paragraph in the "what went wrong" category, but I think this subject deserves its own section. Download and sale numbers for WP7 apps became available on Wednesday 12/08, and I don't think anybody was thrilled. Don't get me wrong: WP7 is a very young platform, there aren't tens of millions of phones in circulation, sale expectations have to be low for now, and can certainly not be compared with those of competing platforms. No, what really surprised me is not the number of sales, but the number of downloads.

On the "top selling" tab of the Zune software (which is more likely based on downloads, like the Bing visual search), Jigsaw Guru has always been in the middle of the paid games from the puzzle & trivia category, the biggest category by far (about 45% of all games). Today for example, it's 174th out of 363. How many downloads do you think this means on average? About 0.65 per day. This totally blows my mind, but is in line with a graph a developer made with the numbers from his 4 apps, that shows the relationship between the marketplace rank and the number of downloads.

One potential problem is it's not obvious enough that lots of paid games support the free trial mode, and some players don't know they can download them for free. But really, it all comes down to most players only checking the XBox Live and the free sections, and rarely visiting the paid one. Which is why although I said earlier that in theory, and thanks to the trial mode, you shouldn't need to make a free version of your paid game, in practice it's obvious this doesn't work, and you have to do it. My friend Noel, who is an experienced iPhone developer, had actually told me I should release my game as a free, ad supported app; unfortunately, the ad SDK's for XNA didn't exist at launch and are still in their infancy, the one from Microsoft got released this month and only serves ads in the US, the other ones are either not finished or not stable yet.

So, what's next? I'm submitting Jigsaw Guru Free (with the Microsoft ad SDK) this week, because as a developer, I still want people to play my game and hopefully have a good time with it. The two projects I started working on after Jigsaw Guru might follow the same path and be free apps from the start, whether it's on the WP7 or another platform.