Glad I didn’t wait any longer to do that

I’m a little peeved at myself right now for assuming that XNA development magically lets you develop for Windows Phone, PC, and XBox360 at the same time without any code changes. I can’t take all the blame for believing this — it’s very strongly implied all over the documentation and marketing literature. Still, today I decided I should figure out now just how the game would look and run on the 360, so I bought my license (more on that in a bit) and started what I naively thought would be a relatively easy process. Hours and lots of code changes later, I got it all working:

Microsoft’s directions for this process make it sound incredibly simple, and conceptually, it was. You start by paying $100 for a subscription to the “because fuck you, that’s why” service, which is required to run games on your 360 in development mode. The actual reason, I think, is that Microsoft wants to prevent a secondary games market revolving around connecting your PC to your XBox, so they make that functionality expensive enough the average non-developer wouldn’t pay it. This was the only part of the conversion process that actually proceeded without a hitch. Thanks for taking my money, Microsoft. You get an A+ on that part of it.

I was surprised to see a bunch of errors in my first attempt to build my converted project. But as it turns out, there are quite a few library incompatibilities when moving from PC to 360. For one, it’s constrained to .NET 3.0, when I’ve been used to 4.0 everywhere (not a huge deal). But more frustratingly, big chunks of functionality in the collections library are just … gone. For example, there’s no such thing as an ISet on the 360 Runtime. There’s also no SortedList, and the List class is missing a bunch of useful methods and extensions like Find() and RemoveAll(). I was confused at first, but once I figured out what was going on, it was relatively straightforward to fix these issues. For example, you can emulate a Set pretty easily with a Dictionary, and in fact Farseer already provides such a class. But be warned: it has a bug in the Add method which will throw an exception if you add the same element twice.

For missing extension methods, I whipped up something like so:

using System;
using System.Collections.Generic;
using System.Linq;
using FarseerPhysics.Common;

namespace Arena.Xbox {

    // Just here to make this namespace non-empty on windows
    public static class Dummy {
    }

#if XBOX
    public static class CompatibilityExtensions {
        public static void RemoveAll<T>(this List<T> theList, Func<T, bool> predicate) {
            List<T> entitiesToRemove = theList.Where(predicate).ToList();
            entitiesToRemove.ForEach(e => theList.Remove(e));
        }

        public static void UnionWith<T>(this HashSet<T> set, IEnumerable<T> other) {
            foreach (T o in other) {
                set.Add(o);
            }
        }
    }
#endif
}

Now I can use normal extension methods regardless of runtime and the right thing will happen.

The final issue was a bit dicier: I needed GZipStream support in order to read the TMX files my map editor produces, and there is no System.Io.Compression namespace in the Compact Framework. Luckily, someone else has a build of System.Io.Compression for CF.

That was enough to get me compiling. Walking around and shooting up the level, as I like to do, I noticed pretty terrible performance when there were lots of physical bodies interacting at once, such as happens when I create a shatter animation. It turns out that XBox 360 is just a lot worse at crunching floating point numbers than even a moderate PC is, and there’s really not a lot to be done but tune your game to scale back the demands placed on the physics engine. In my case, that means reducing the number of shards produced from a shatter effect by 75% when targeting the 360:

#if XBOX
                    int numPieces = 4;
#else
                    int numPieces = 16;
#endif

It still looks nice on the 360 with this simplification, although some of the wow factor goes away, obviously. There may be some other knobs on Farseer that I haven’t learned how to twist yet — my initial tweakings didn’t seem to make much of a difference.

So that wraps it up for the initial XBox 360 port. I don’t wish I had done it sooner, but I’m glad I didn’t put it off any longer. I can’t even imagine the deep depression I would enter if I had waited until the game was finished to discover all this work.

Leave a Reply