2010-09-30

Divide and Conquer

In my previous post I discussed how I found a way to edit my iOS MonoDevelop (MD) projects in Visual Studio (VS) on my PC, but that I could not compile there and wanted to fix that. In this entry to discuss my solution.

At it's heart the problem is that by default iOS projects reference the MonoTouch (MT) library that wraps the standard iOS libraries (Cocoa, Core*, etc). These projects also have some special configuration options for iOS devices that VS doesn't like. Furthermore, if you are creating a typical iOS application then you probably need to interact with the MT libraries a lot. On the other hand, if you can divide your project into we separated layers, then all but the device specific functionality should be able to exist in standard .NET code and be fully compilable in any platform. That is exactly what I did.

Initially I had a single .NET project with 3 main components:
  1. OpenGL setup - A modified version of the default OpenGL related classes provided when you create a new MT iOS OpenGL solution. The modifications are relatively minor, although they do include also setting up OpenAL.
  2. Graphics and Sound utilities - Classes I'd written to provide some more object oriented constructs for base graphics and sound functionality. For example, I created a simple Texture class that was simply a set of coordinates that defined a triangle in the OpenGL world along with its matching triangular coordinates of the texture to show there. Another example is an AudioSample class that encapsulates an OpenAL audio sample that can be played, stopped, etc.
  3. Game logic - The actual game related components of my game.

So, what I did was to separate these 3 components into separate projects with only the first one referring to the MT library. In addition I created a new version of the first component that was compatible with the PC. If you're paying attention you might wonder about how I could create a PC project that relies on OpenGL ES (ES is the version of OpenGL that is for mobile devices) and on OpenAL, neither of which are standard functionality in Windows. I'll go into some details of this in future posts, for now I'll continue the discussion of the project reorganization.

I should mention that this project separation includes the unfortunate requirement of having parallel project (.csproj) files, one for MD and one for VS. This means that anytime I add a new file to my VS project I need to eventually add it to the MD one as well. Fortunately these new files quickly show up as missing when I compile, so it hasn't been too much of a burden yet. I do hope that MT supports VS better in the future, though.

On the coding side, one of the challenges I faced was that I didn't want to have anything in my first 2 projects that was specific to the game I'm writing. All of that should be only in the 3rd project. At the same time, the loading of data into my Texture and AudioSample classes is platform specific. For example, on the iPhone it is recommended that you have you audio files in CAF format. On the PC WAV is more typical. Also, UI interaction is platform dependant. Specifically the iPhone provides multi-touch events and the PC mouse events. Fortunately, it turned out to be relatively easy to handle all of this.

For the Texture data loading I simply pass a Func<string, Texture> to my main game class' constructor. This takes a string (the filename of the texture data) and returns a fully instantiated, platform independent Texture object.

Similarly, for the AudioSample I pass a Func<string, AudioData> that does that same but returns a platform independent AudioData object.

Finally, for the UI interaction I just have few methods on my main game object that are called for touches/mouse event. At this point I don't have any interaction that is iOS specific (i.e., multi-touch) that is not possible on the PC. If I get to the point that this is required then I'll have to come up with a work-around for the PC side.

One thing that's implied in all of this is that I did need to implement the texture loader and sample loader twice, once for each platform. This is true, but was relatively simple. One other huge advantages of dividing my projects in this way now is that I'm setting myself up well to support Android and Windows Mobile 7 devices later. Although, I should mention, I am still writing my game classes with a certain amount of reliance on OpenGL, so porting this to another graphics framework would probably be a bit more work (Does Windows Mobile 7 have OpenGL or some mobile DirectX?).

Next time: OpenGL ES 1.1 on Windows.

P.S. One other note on this...
My initial version written in MD on the Mac used standard .NET System.Drawing.PointF structs to keep track of coordinates. Unfortunately, I ran into a problem with this when I separated my projects. Apparently MT does not include a full implementation of System.Drawing and only bundles a few parts inside the main MT library. This means that when I separated my platform independent project for which I did not want a reference to MT they also lot their reference to PointF. My solution was to change to use OpenGL's Vector2 struct, which is basically the same, although it is one of the reliances on OpenGL that I mentioned above that I would prefer not to have.

No comments :

Post a Comment