Monday, 6 December 2010

Normality, Of Sorts

It's been one month since Jenna and I moved into our new home. We're still in the process of sorting everything out, and we're still having to move boxes of junk in from our parents' houses and find room for everything. Luckily we have a huge loft for most of the boxes of knick-knacks. We've somehow found the time to put up the christmas tree and a few lights already! It's all feeling much more homely now, and having done the major work, I've been able to sort out a schedule for Team Mango game development work.

It's a rough schedule that allocates days to certain tasks, but doesn't constrain me to allotted hours, because I never know how many hours I'll get to spend in any given day. Still, my schedule goes something like this:

Monday - Blog post day
Tuesday to Friday - Work on Game 4 for Phone 7
Saturday - Bring Windows and Xbox versions of Game 4 up to date
Sunday - Work on Dysnomia for Phone 7

Bear in mind that I usually have only one or two hours each day to spend on the assigned task. I kind of like it like that, as it allows me to really focus on bitesized chunks of work.

I tend to treat Saturday as my "anything goes" day, as it's the one day I have plenty of time to spend on development. The only task I set myself as must complete for Saturday is to get the Windows and Xbox versions of Game 4 up to the same level as Phone 7.


Throughout the week I develop on the phone as it's the lead platform for Game 4, but I'm giving the Windows and Xbox versions the same amount of respect by making sure I carefully tune the UI and controls for each platform. Sometimes this may only take 20 minutes on a Saturday morning, adding in any new content files and tweaking the controls. Sometimes it takes longer, especially if there's new UI items to do - especially on the 360, where I need to display button prompts rather than having clickable/tappable buttons on-screen. There's a lot more to developing on all three platforms than simply creating copies of a project in a solution and hitting compile!

So that's my work schedule - but how do I remain focused? Like many creatively-minded people the world over, I tend to have moments of procrastination. It's easy for the mind to wander to other things. Here's my top five tips for staying on a project, especially if it's just a hobby:
  1. Work with someone else. There's absolutely no substitute for teamwork. If you're working with a partner on a project, you're always pushing forward because you don't want to let the other party down. I have Leon constantly churning out art assets for our games, and that pushes me to get things done.
  2. Work in bite-sized chunks. If you know you've only got an hour to spend on something, plan ahead and assign yourself a task you know you can get done in that hour. Conversely, if you have a full day - don't spend all of it working. Work on a large task that might take five or six hours, but have plenty of breaks. And when you're done on a task, it's okay to call it a day. If you feel you've accomplished something, then it's probably a good time to stop.
  3. Music. This is a personal thing, but I find that music helps me concentrate a lot more, especially if I'm listening to familiar tunes. I often find I have the same few albums in rotation for several weeks before I try something new. For the record, I listen to a lot of melodic death - but whatever floats your boat!
  4. Get a whiteboard! I love my whiteboard. I use it to keep track of tasks, doodle UI sketches and work out geometry math. If you don't have room for a whiteboard, you may find a pen and a pad of paper a suitable alternative.
  5. Do the hard and/or boring stuff first. Specifically in games development, there's the cool stuff like gameplay, animation and visual effects. Then there's the monotonous stuff like menu screens, file handling, Xbox profile support, tutorials and so on. Reward yourself for completing something boring by working on something cool. Otherwise, you'll finish your main game after several months, and still have a month's worth of essential polishing to go, when all you want to do is get the game out the door.

Monday, 29 November 2010

Tombstoning in Phone 7 XNA games

One of my pet peeves about the new Windows phone 7 platform is incorrect or insubstantial use of "tombstoning" of applications, especially when it comes to games. Tombstoning is the terminology Microsoft use to describe the hibernation of apps when they lose focus (ie. for an incoming call, or the start button being pressed).

In a way, some of the worst culprits are the official Xbox Live games on the Phone 7 marketplace. Very few of them will resume the game at the exact place they lost focus. Take one of my favourite titles, Rocket Riot, for example. It's one that almost gets it right, but falls at the last hurdle.

Each of Rocket Riot's levels requires that the player kill X number of enemies, 50+ in the late game. If the game loses and then regains focus (ie. it is tombstoned), it remembers which level was being played, but not the number of enemies that had already been killed, or the progress of a boss fight on boss levels. The player is effectively forced to restart from the beginning of the level, and is in a way punished for taking a phone call or accidentally brushing against the start or search hardware buttons.

Some of the Xbox Live games don't even behave that well. Having to sit through splash screens and 30 second long loading screens just to get back to a game that simply lost focus is just not good enough. And as responsible XNA developers, we can make sure our games behave, and it needn't be a complete hassle to achieve seamless tombstoning.

The XNA team give us a great starting point in the Phone 7 Gamestate Management sample. There's even more help available in the article on Tombstoning in WP7 Games.

I use a modified version of the Gamestate Management sample as a starting point for all my XNA projects, whichever platform I'm working on at the time. I found the Phone 7 version of the sample to be very useful, although in its current incarnation, it doesn't quite push the tombstoning quite far enough.

I changed the sample to recognise the right startup event for restoring state upon re-activation. There's a handy table in the Tombstoning in WP7 Games article. The Gamestate sample does not check the PhoneApplicationService.Current.StartupMode property, and instead attempts to restore from a tombstoned state every time the game is run. To avoid this, we simply need to add a check in Game.cs as follows:

Replace:

// attempt to deserialize the screen manager from disk. if that
// fails, we add our default screens.
if (!screenManager.DeserializeState())
{
// Activate the first screens.
screenManager.AddScreen(new BackgroundScreen(), null);
screenManager.AddScreen(new MainMenuScreen(), null);
}

With:

// attempt to deserialize the screen manager from disk. if that
// fails, we add our default screens.
bool deserialized = true;

if (PhoneApplicationService.Current.StartupMode == StartupMode.Activate)
{
if (!screenManager.DeserializeState())
{
deserialized = false;
}
}
else
{
deserialized = false;
}

if (!deserialized)
{
screenManager.AddScreen(new BackgroundScreen(), null);
screenManager.AddScreen(new MainMenuScreen(), null);
}

You'll need to add a reference to Microsoft.Phone, and also System.Windows (the latter is required for the IApplicationService interface). You'll then need to add the corresponding using statement in Game.cs:

using Microsoft.Phone.Shell;

Great! now the Gamestate sample will only attempt to restore from a tombstoned state upon re-activation, not starting afresh. Now onto the tricky stuff.

The Gamestate sample rather cleverly serializes the state of all the opened GameScreens when the game is Deactivated. This means we don't have to do anything extra to get back to the screen (most likely GameplayScreen) that was in use at the time of deactivation. If the Xbox Live games mentioned earlier are anything to go by, you've done enough at this point! Go straight to marketplace, do not collect £200.

But in order to cater for the more discerning phone user, we need to do more work. We need all of our game objects to be saved as they are. We want our main character to come back exactly where we left him. We want to be on the right level, and with the same enemies in the same places. Now all of this is going to depend on your game and how you intend to handle game saves, but I will give an example of just one way to do it, using XmlSerializer.

The GameScreen base class has two overridable methods, Serialize() and Deserialize(), which are called when the screen is removed or added during application Deactivation and Activation respectively. So, in our GameplayScreen, we need to add both these methods:

public override void Serialize()
{
base.Serialize();
}

public override void Deserialize()
{
base.Deserialize();
}

Now, let's assume that you have a game hero class, Hero. Your GameplayScreen might instantiate the Hero class:

Hero gameHero;

public GameplayScreen()
{
gameHero = new Hero();
}

And during the game, the hero's fields might be updated, such as gameHero.Position, gameHero.Level and so on. We need to save the state of the Hero class when the game is deactivated, and we're going to use XML serialization to do it, because it requires very little work to get up and running.

Let's extend our earlier GameplayScreen.Serialize method to store down our Hero when GameplayScreen is serialized (the game is being tombstoned):

public override void Serialize()
{
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!storage.DirectoryExists("TombstoneData"))
{
storage.CreateDirectory("TombstoneData");
}
using (IsolatedStorageFileStream stream = storage.CreateFile("TombstoneData\\hero.dat"))
{
XmlSerializer xmls = new XmlSerializer(typeof(Hero));
xmls.Serialize(stream, gameHero);
}
}
base.Serialize();
}

It's as simple as that! We open up the application's IsolatedStorageFile, create a directory in it, and serialize the gameHero instance of the Hero class to XML, which we then write out to the hero.dat file stream. And because all .NET 4 classes are automatically marked as Serializable, we don't need to do any extra work to save out most of the fields on the class.

We can now do the opposite to load our hero back in when the game is activated, and the screens are Deserialized:

public override void Deserialize()
{
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
try
{
using (IsolatedStorageFileStream stream = storage.OpenFile("TombstoneData\\hero.dat", FileMode.Open, FileAccess.Read))
{
XmlSerializer xmls = new XmlSerializer(typeof(Hero));
gameHero = (Hero)xmls.Deserialize(stream);
}
}
catch (Exception ex)
{
if (storage.DirectoryExists("TombstoneData"))
{
string[] files = storage.GetFileNames("TombstoneData\\*");
foreach (string file in files)
{
storage.DeleteFile(Path.Combine(loadFolder, file));
}
}
}
}

base.Deserialize();
}

We add the extra try/catch to handle any errors that may occur whilst loading our data back in. If it fails, we simply delete any remaining files to clean up the TombstoneData folder for next time.

Now, it's important to know in which order the GameplayScreens initialization methods get called when returning from tombstone. The ones we're concerned about (in order of execution) are:

  • The constructor GameplayScreen()
  • Deserialize()
  • LoadContent()
So we should instantiate our game classes in the screen's constructor, load their saved state in Deseralize(), then load any graphical content in LoadContent(). You'll probably have a Hero.LoadContent() method, which you'd call from GameplayScreen.LoadContent().

Of course, there's a lot more to tombstoning than simply serializing your main classes, but hopefully it'll give you a starting point to help improve your game's behaviour. There are issues with the performance of the XmlSerializer and you may choose to look to Binary serialization for instance.

I'm only just scratching the surface whilst developing the as-yet-unannounced Team Mango RPG for the phone, so I'll likely blog more about my final tombstoning solution as it's quite a black art that unfortunately even the big studios are failing to get right.

Monday, 22 November 2010

Shrinking Dysnomia

In my last post, I teased Dysnomia running on Windows Phone 7. It's an interesting challenge, shrinking the game down to run on the phone. I did a lot of optimization on the 360 version, mostly around garbage collection and memory management while the gameplay was running.

What I did not optimize at all was RAM usage. I chose to load all game assets up-front, even before the title screen appeared. For the 360, the amount of overall RAM used was trivial, and the load times were fast. I loaded all animation spritesheets, all sounds, all music and all popup screen content before the first level was started.

The only items I chose to load per-level were the tilesheets, as they were by far the largest textures used in the game, and I needed to be able to free up the RAM they used between levels.

On the phone however, the RAM usage story is completely different. Microsoft recommends that an application shall not exceed 90mb of total RAM usage, that is to say peak usage. It's a simple matter to check how much memory your app is using:

var curuse = (long)DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage");
var memuse = (long)DeviceExtendedProperties.GetValue("ApplicationPeakMemoryUsage");
var maxmem = (long)DeviceExtendedProperties.GetValue("DeviceTotalMemory");
curuse /= 1024 * 1024;
memuse /= 1024 * 1024;
maxmem /= 1024 * 1024;

Will return current memory usage, peak memory usage, and total RAM available (in MB) respectively.


So when I hooked up a debug method to output the RAM usage to the screen, I discovered that Dysnomia was using 190MB at peak (with the map screen open), and 170MB during normal gameplay. That's twice the usage limit for passing app certification!

I began by simply cutting down on front-loaded assets. Later on, I'll implement per-level loading of required spritesheets, but for now I've simply eliminated loading of everything not needed for the first level. That alone got me down to around 110MB peak usage.

Next up, I began resizing all of the sprite and tilesheet textures. An across-the-board resize of 75% got me down to around 80MB peak. Several larger spritesheets could be downsized even further. Next up, I stopped loading variations of HUD and player sprites for different player colour options and for player two, as there will be only one player on the phone.

After all that, I'm currently down to 75MB in-game, and 80MB or so on the map screen. I'm still investigating further reductions, including using DXT compression for spritesheets. My target is 65MB in-game usage before reinstating sound effects and boss fights, which will require a good 10-15MB of RAM per level on top of what's used already.

I'm not going to officially confirm Dysnomia for WP7 until I'm sure I can make it work, but so far I'm impressed with the virtual sticks (emulating left/right thumbsticks via the touchscreen) I've implemented, so I'm sure it will control quite nicely if I can just get everything squeezed into RAM.

Game 4

Can't wrap up this post without a quick update on Game 4. I've resumed work on the next Team Mango game, working on it alongside Dysnomia for WP7 and Run! for XBLIG. It's an RPG, and the next job I needed to complete was getting an enemy manager up and running. The manager controls all of the enemies loaded on a map, including their spawn points.

As the game is based upon my XNA Tile Engine solution, I'm using the Tiled editor to lay out the area maps. To depict enemy spawns, I'm using an Object layer. The screenshot below shows a typical map layout with spawns. Each rectangle represents one enemy's patrol area, with the spawn point in the center. When the enemy is loaded, a point within its rectangle is chosen at random, and the enemy begins to move toward that point. When it reaches its destination (or collides with a wall), it chooses a new destination point from within its rectangle.



And the result, Squirrels!

Monday, 15 November 2010

Moving House and Team Mango projects for the next year

I'm almost done with the house move. That is to say - we're in, but still living out of boxes while we wait for a few bits and pieces to come together. It's not been the smoothest of moves, especially having our garage broken into no more than two days after spending our first night in the new place. Nothing too essential gone, but all of my guitar amps and effects were taken. I was planning to sell them next year to fund a new PC, so it looks like that may be on hold for the time being.

Anyway, troubles aside the new house is looking great and I now have a spare room studio setup for working on all the Team Mango projects that I've been planning for the better part of half a year while all the househunting and moving was taking place. Here's a dark picture of my workstation:


I need to do a bit of housekeeping in this post, starting with an update on 7Cache, my Phone 7 Geocaching app. I've decided to suspend the project for now, because Groundspeak released their official Geocaching app for the phone, and it seems to have everything most 'cachers would need including offline caching. It's quite well presented and seems to work well, though I have yet to get out and test it properly on a full day's caching. It certainly has more features than I planned for 7Cache, apart from the Cache Radar function. I rarely used that in Geocache Navigator anyway.

I may revisit this decision further down the line if there's a niche for features that Groundspeak won't add to their app, or if they make the Geocaching.com API publicly available. For the time being, I have game projects to work on and that's where I'd rather spend my very limited personal time. Speaking of which...





That's Run!, the third game from Team Mango. It's been in the works since February, just before Dysnomia hit Xbox Live Indie Games. I've been working on it sporadically, but it's close to being ready now.

I'd describe it as "Skyroads with Avatars", and it offers 1-4 players local competetive play as well as online best times, using the same highscore sharing method employed by many XBLIGs. I'm looking forward to finally getting it out the door after a busy few months away from all things Indie Games.

The fourth Team Mango game remains under wraps, but I can say it's an action-RPG, and will be released for Phone 7, XBLIG and Windows sometime in 2011. It should also be pretty damn funny, but I guess that's subjective!

Also,


Friday, 22 October 2010

Windows Phone 7 Device Get

Just a quick post with some images of my Samsung Omnia 7, running my two current projects: 7cache, and the next Team Mango game. I'll post more on the phone and the projects once I've finished moving house ;)

Saturday, 2 October 2010

XNA Tile Engine Base Solution Updates

I've done a little more work on my XNA Tile Engine for WIndows Phone 7, and I've also branched it off into a solution for Windows and Xbox, which I've dubbed "HiDefTileBase".

The HiDef solution contains an additional example mode showcasing a platform game running on the engine. It's important to note that both the RPG and Platform examples are using the exact same classes for drawing the tilemap and controlling the camera - only the GameplayScreen and Player classes differ to reflect the actual game mechanics.


I've added an example of a day/night cycle into the RPG game in both the Phone 7 and HiDef solutions, and made some optimizations to the map drawing routine as it was getting rather slow when several layers were being drawn. All looks good now, although performance on Phone 7 hardware is still a mystery :)

The two new downloads are after some screenshots:




Please note that the solution is built on XNA 4.0 and will not compile using older versions of the XNA SDK.

Hi-Def (Xbox & Windows) solution: http://team-mango.com/stuff/hideftilebase.zip


Tuesday, 28 September 2010

Phone 7 XNA Tile Engine Base Solution

A lot of the game ideas I have require a tile engine as a base. I've had a few ideas for Phone 7 games but thus far I've given up at the first hurdle - a tile engine.

I've now resolved that issue by creating a base solution with a ready-to-go tile engine that is suitable for side scrollers, top down and RPG-style maps. I've decided to release it so that anyone else in my position should be able to pick up this base solution and get cracking on tile-based games.

The solution imports maps created with Tiled.

Here's a video of the engine in motion:



And a handy list of all the features of the solution:
  • Suitable for side-on and top-down games
  • Good for platformers, RPGs, shooters, racers, adventures - anything that needs tiles!
  • Works in landscape or portrait with one line change.
  • Built on the Windows Phone 7 XNA Gamestate Management engine sample.
  • Uses Nick Gravelyn's content pipeline extension for the "Tiled" editor.
  • Simple but flexible camera class that clamps to the map boundaries.
  • Draw the whole map at once, or one layer at a time for flexibility.
  • Parallax scrolling simply by adding a couple of properties to a layer in Tiled.
  • An overload to draw a layer as "shadows" by drawing offset+black+semi-transparent.
  • Per-pixel colour-based collision detection on specified layers/tilesets.
I've added a whole bunch of comments to hopefully help some beginners along the way. Please note that this is just a base engine for a game, and won't help you magically write your actual game mechanics!

This is the first time I've released some code with the intention of helping other developers, so please leave comments below. I'll address any questions in future posts. If anyone with a real device reads this, please consider giving it a run on a real phone - I'd love to know how it performs (if it runs at all!). Take some video as well!

A few screenshots next, download link is at the bottom of the post!



Tiles used in the solution are released freely at Lost Garden.

Please note that the solution is built on XNA 4.0 and will not compile using older versions of the XNA SDK.


Monday, 6 September 2010

7Cache - New screenshots

Lots of work done this weekend. .GPX importing from Windows is working (in theory!). Also implemented direction and bearing to both the active cache and any cache you select from the map. Distances can be displayed in metric (km/m) or imperial (mi/ft).

Edit (Tues 7th): Added Cache Radar screenshot!



Friday, 3 September 2010

7Cache - Planned Features

Work continues on 7Cache - my Windows Phone 7 Geocaching application. I've compiled a list of features that will make it into the first release:

  • Import of .GPX pocket queries via a companion desktop application.
  • Offline storage of around 2-3000 caches, including descriptions, hints and recent logs. You won't need a data signal to find caches you've pre-imported!
  • Bing Maps integration. View caches on a pan/zoomable world map, find caches near your location quickly.
  • Full details of each cache: descriptions, recent logs, hints, cache size/terrain/difficulty, distance and direction to cache.
  • Cache Radar - similar to the radar function in GCzII and Geocache Navigator, shows distance and direction to cache, along with your direction of travel. Will have an optional audio "click" as you get closer.
Some of the must-have features that will make it into the app in the future, as soon as it's possible to do so:
  • Download caches directly from Geocaching.com with a "find caches near me" feature, fully integrated with the Cache Map.
  • Log your finds directly to Geocaching.com.
  • Integrate phone compass with cache radar so there's no doubt about which way to head.
  • Import .GPX files from Skydrive, Windows Live's online storage facility that will be used to share content with all your Windows devices.
I'll be posting some more screenshots this weekend. I'd like to hear suggestions from any prospective Windows Phone 7 Geocachers about features that you'd like from a mobile 'caching app. Leave a comment!

Sunday, 29 August 2010

7cache - Geocaching App for Windows Phone 7


Microsoft is ramping up to the release of Windows Phone 7, and they've really been pushing the developer tools recently. The tools for WP7 development are now packaged alongside the XNA Game Studio 4.0 previews. I can see the reasoning behind it - WP7 development is either Silverlight or XNA and you'll use the same tools to develop XNA games for Windows, Xbox and Phone.

What makes less sense is that the Silverlight applications development side of the WP7 tools are also bundled in with the beta, creating an odd mishmash of tools for WP7 apps, WP7 games, as well as Xbox and Windows games development.

If Microsoft were hoping to tempt some of the XNA community over to Silverlight, they've succeeded! I briefly touched on Silverlight back in the 2 beta but I thought I'd have a dip into creating an application for Phone 7. I also intend to explore cross-platform games development for the phone and Xbox at a later date.

I've decided to create an application for Geocaching on the phone. In a nutshell, Geocaching makes use of GPS technology to create a worldwide outdoor treasure hunt. Geocaching.com holds a database of "caches" placed by Geocachers around the globe, and provide the data for users to hook up their handheld GPS unit or GPS-enabled mobile phone and go hunting for caches.

The best mobile Geocaching application I've used is Trimble's Geocache Navigator on my Nokia N95. I'd like to get all the features of that particular application into my app, while providing a modern easy-to-use interface that makes the Geocaching-on-the-go experience a pleasant one.

And so I've begun prototyping my first Windows Phone 7 application, 7cache.



It's a good project as it not only exposes me to more Silverlight, but it also makes use of many features of the the phone, including GPS, mapping and (when made available in the API) the compass.

Unfortunately, while I can develop out the application to be as feature-rich as most Geocaching applications out there, I may never be able to release it as a real product. To be of any use, the application must be able to bring in XML data about the caches themselves. In other applications, this happens in one of two ways:

1. The user uploads .GPX waypoint files to the phone, and the application reads them in. Or:
2. The application connects to Geocaching.com's API and retrieves cache data directly.

The first method is not possible on Phone 7, because Microsoft is not allowing direct access to the filesystem either by users or third party apps. I was hoping to make use of the rumoured Skydrive integration, but the API is currently limited to retrieving pictures from a user's Skydrive. I could leverage Azure services, but that would require users to go through a Windows application or hosted website to get their GPX files to their phone, which is an unwanted layer of abstraction.

The second method would be ideal, if Geocaching.com made their APIs public. At the moment, only selected partners are able to query the Geocache database directly in their applications. They have said they are looking at opening up the APIs to a wider audience in the future. If they do, I'll be waiting with a near-complete solution for Phone 7 users.

Of course, there's other obstacles to overcome - I'll need a physical device to implement real geolocation properly. It's possible to fake it in the current API, but in order to build out the "cache radar" function, I'll need to test on real hardware. Having said that - so far the emulator is doing a great job!

On another note, I should really stop starting new projects!

Friday, 20 August 2010

Dysnomia: The Post-Mortem




Before I begin with this post, I should say that I am more than happy with the successes I have achieved with Dysnomia. I set out in May 2009 to create a game that I could be proud of, and that I would enjoy playing. I had no thoughts back then of making money from selling the game on the Xbox Live Indie Games (XBLIG) service, where my first release Gravsheep had failed miserably.

Dysnomia was born out of a love for '90s Amiga games, and those in the know immediately liken it to Team 17's Alien Breed. I did indeed set out to make an Alien Breed-alike, but there was another much less-known game that I borrowed ideas from. That game, Xenomorph, was a Dungeon Master-like crawler RPG set on a mining outpost. In fact, reading the game's Wiki article it's scary exactly how much I borrowed from it!

So the top-down, alien-shooting arcade action was borrowed from Alien Breed, whilst the parts-collecting and puzzle-like elements were borrowed from Xenomorph. The game's speed and sheer number of enemies on-screen was kind of a throwback to Gauntlet, but that came about naturally as I added in dual-stick shooter controls. Early in development, the right stick was unused and the player could only shoot in the direction of travel. That's one early change I'm glad I made.

I began in May with a design document that gave an initial outline for the game, and gave me something to show to potential artists that applied to my request for help on the Creator's Club forums. I believe that having that document showed artists that I was semi-serious about the game even though I was only offering a 50/50 profit split. I was pleasantly surprised at the number of replies, but at the end of the day one guy stood out from the crowd simply by getting the game idea and throwing out a few initial tilesets, some concept art and a character animation. That guy was Leon, and without him Dysnomia would be nothing more than a long-forgotten Visual Studio project folder.




And so the two of us ventured forth with development. One of the very early jobs for me was to enhance the level editor I had hacked together for Gravsheep so that it could be used to design the levels for Dysnomia. The editor was a simple Windows Forms affair, with drawing handled in GDI as opposed to using WPF or an XNA window. So, not the fastest of editors, but it worked well enough for both myself and Leon to get the levels done.

There are nine levels/floors/areas in Dysnomia, and each one was saved out of the editor as a simple plain text file using 2D arrays of three-digit integers to represent the tiles. Each map has a set number of layers overlaid in a set order. Some of the layers were full-colour tilesheets, others were effects layers. Later on I added in animation layers which were used sparingly, the biggest example being the animated water on the Maintenance level.

If I had to go back and do the editor again, I'd do it in Silverlight to start with. I'd allow for an unlimited number of layers each with a specific effect applied (shadow, reflection etc). I'd allow for multiple tiles to be selected in the tile palette and pasted into the map (large objects made up of several tiles had to be drawn tile-by-tile!). I'd make it a lot more generic too. Like I said though, it did the job and allowed me to focus on the game.



Developing the game itself was a veritable minefield for this amateur developer. Although I've been messing about with games development since the Acorn days, this is really the first serious game that I've attempted. Instead of playing it safe and skirting around issues I knew would be a challenge for me, I ploughed through. I implemented some features in Dysnomia that I never thought I'd be able to write. The one that immediately springs to mind is the pathfinding AI.

I hadn't even considered that the aliens might actually need to be able to find their way to the player. I guess I'd hoped that the Gauntlet-style logic of "move toward player location until you hit a wall" would suffice. Not really, no. It became apparent that some basic intelligence would be required. I knew nothing of the various pathfinding techniques that developers had used over the years, and I only just managed to understand A* after a few days of reading.

Luckily, Roy Triesscheijn has done a lot of work implementing A* in C# and XNA. I was able to leverage his examples as a good starting point. There was an awful lot of work to do to even with that initial code as it was quite allocation-hungry, and of course I had to make it work with my tilemaps. It all came together in the end though, and I could probably write a whole post on how.

There were a number of other challenges that I won't go into detail on here. Performance was a big one, and I learnt how to use the XNA remote perfmon tool and the .NET CLR profiler together to banish allocations and garbage collections. For those interested, I went down the path of allocating everything during load and nothing during the game and it worked wonders.


And so onto the game itself. The game received a number of awesome reviews, which I was so happy with. To see something that you poured so much love into be received so highly was reward enough. It went down fantastically with the Creator's Club members that playtested and reviewed the game. Receiving praise from peers is even better than getting good reviews!

Then the unthinkable happened - Dysnomia placed in the top 20 of Dream Build Play 2010! Leon and I decided to enter the game on a whim, and it just happened that we were mere weeks away from a complete and polished game when the deadline rolled around. That definitely worked in our favour. Although we didn't get a cash prize, Dysnomia became eligible for a place on the "Contest Finalists" section on the dashboard. More on that later.


One of the more common comments about the game is the respawning of enemies. In Dysnomia, the only enemies that are gone completely once killed are the bosses. All of the other enemies are spawned constantly, so there's always something to shoot. Many players didn't like that, and suggested that once the player clears a floor, the respawns shouldn't happen - or at least occur less frequently.

Looking back on it, I agree. If I was doing it all over again now, I could create a more tense and atmospheric game by using spawns more intelligently. Combine that with better use of the lighting system and it could have been an entirely different experience. The fact remains that Dysnomia definitely became more of a standard frantic dual-stick shooter than a story-driven adventure shooter. Maybe next time?

On a more personal level, I would have like to have used the motherboard/device mechanic a lot more. Motherboards in the game were inserted into and removed from devices such as doors, terminals, turrets and switches to power them up and down. The initial idea was to have more of those devices so the mechanic would become almost puzzle-like. If combined with less frequent enemy spawns, more motherboard/device puzzles would have been great. However, I think due to the overall speed of the game the frequency of the puzzles was just right. Any more and the player wouldn't have had time to solve them in between bouts of shooting!


And now to the boring business side of things. Dysnomia cost me around 800 hours of my time, and probably the same of Leon's. We couldn't possibly hope to make enough money to pay us a full wage for that much work. Good job this is just a hobby, right?

I spent around $100 total on assets for Dysnomia. Most of that went toward the sound effects I purchased from Soundrangers. That's right - I created a nine-level, three hour or so long indie game for $100. That's £70, give or take. So if you're looking purely at the bottom line financially, Dysnomia has made about ten times what was spent on it so far.

The music was mostly free-to-use public domain stuff composed by Matt MacFarland. The title track was made by one of the original members of Team Mango (as it existed back in high school), Adam Bartlett. The in-game ambient track was purchased from Shockwave Sound and composed by Bjorn Lynne (who wrote a lot of music for Team 17 and the theme music for Alien Breed 3D).

As I said, Leon agreed to do the artwork based on a 50/50 profit share, and I was lucky to find an artist that has the same passion for making games that I do. Any money we make is great, but it's not our focus at all.

And so, to some numbers. Here's a pretty chart:


Fairly self-explanatory. Firstly, not a great conversion ratio of around 6%. Secondly, you'll notice that huge trough between the end of March and the middle of June. End of march is when we dropped off the Indie Games new arrivals dashboard list after the first ten days or so. We then had very few sales and trials, most of them were driven by the reviews we were getting.

On the 15th June, the game was promoted to the Contest Finalists section of the dashboard, and that's where things pick up again. Sales aren't quite what they were in the first week, but the conversion ratio is similar. We currently average around 4.5 sales/day. I expect the sales to continue this way until we're pushed off the Contest Finalists section sometime next year.

Here's the totals for 19th March - 18th August:
  • Trials: 8002
  • Purchases: 487
  • Purchase/Trial Ratio: 6.09 %
So, we're nearing 500 sales fast. My personal target for Dysnomia was 1000 sales, and it looks like we'll reach it if things stay as they are now. What's more impressive is that 8000 people out there have played (or at least downloaded) my little game!

What makes me a little glum is thinking about where we'd be without the DBP placement. Sales and trials were dire in April and May when we weren't on the dashboard top lists. Even with some great word-of-mouth, we were nowhere. It goes without saying that if we were looking for financial success, XBLIG was not the place to find it with a game like Dysnomia.

I priced Dysnomia at 240msp. It's the price point of a quality XBLIG game that actually wants to sell some copies, which would not happen at 400msp. I think it's a fair price. When we drop off the Contest Finalists section, I'll drop it to 80msp. That's fairly selfish (and probably quite mad!), but it'll be a reasonable experiment to see if a quality game like Dysnomia can make some sales when not on the top lists. Should be interesting!

So there you have it. Dysnomia in a (rather lengthy) nutshell. The best game I've ever made and some of the most enjoyable coding I've ever done. I improved as a developer by an order of magnitude whilst writing it, and will always look back on the process fondly. Financial success maybe not, but a personal triumph indeed.