The Great Porting Adventure: Day 8

After a few days off, The Great Porting Adventure resumes!

The TODO list has reached equilibrium – new items are discovered at about the rate that I knock them off. I figure this is a good sign, since I’m getting a handle on the remaining work and the issues that do pop up are pretty minor. Porting is a bit of a grind though. I’d much rather be working on something new and exciting at this point. The novelty of seeing my game running a Mac has all but worn off and thus I didn’t spend much time on it this week.

I started by going through the list of things that I compiled out just to get the game running in the first place. The big one was the intro “studio logo” splash which was a screen with a bit of transition flair that shows up when the game starts and loads a bunch of assets behind the scenes. I had to basically rip this out at first because it was causing a crash somewhere in OpenGL, which was about two levels of framework lower than anything I understood.

Is my code broken? Or XNA? MonoGame? MonoMac? maccore? OpenGL?

I read into it a bit and it turns out that OpenGL does not like it when you use an OpenGLContext from a different thread. This was a straightforward fix (a MakeCurrentContext() in the right place in the worker thread) because my use case was pretty simple: main thread loads assets, worker thread updates and draws the logo animation. This fixed the crash, but rendering had some serious issues. The screen fade was functional, but debug text was popping in and out over top of it. The logo itself wasn’t showing up at all, even though it was drawn in a very similar way to the screen fade.

It would eventually be revealed that none of these issues were related to OpenGL nor my multi-threaded use of it.

I spent a while trying to figure this out and lamenting the lack of PIX. At one point in my debugging, I noticed that I was multiplying some Color values by an alpha that was outside [0,1]. This turns out to be a no-go in MonoGame. I didn’t look into it much (and I don’t have the source in front of me), but I’m guessing it has something to do with the packed value representation used for Color. Not sure – needs more investigation. Certainly not the source of problems I was expecting.

The inconsistent rendering order that was causing sporadic popping of components was due to the draw order not being respected in the Game class. Or rather, the implicit draw order based on the order you added components was not always being honored. I fixed this one by explicitly assigning a DrawOrder to my components, which fixed the sorting.

After a while wrestling with this, I realized that my loading scheme was really just overly complicated and kind of hacky. I had pulled it from a previous game that loaded a lot of things up front, but the use case for DLC Quest wasn’t the same. There was no need for a second thread, and there certainly was no reason that it should be calling Present() on the GraphicsDevice. I’m pretty sure it came from the NetRumble sample, but it still felt wrong to be circumventing the Game loop like that. At any rate, I ripped it out and switched to a much simpler “show logo animation, then press start screen, then load stuff” flow. Much better.

The fiddling continued as I worked to get rid of some “dirty frame” transitions. It seems like there are some cases where I need to clear the framebuffer that don’t crop up in the XNA version of the game. I’m not sure where the discrepancy stems from, but it was easy, cheap and pretty logical to add in a Clear in one or two places. One transition problem stemmed from my use of ResetElapsedTime() to avoid a hitch after spending a long frame loading content. This method isn’t implemented in MonoGame at the moment, but I didn’t dig deep enough to find out if MonoGame would try to “catch up” on long frames anyway. It was easier just to add a few more frames to smooth out the transition.

Oh, and SoundEffectInstance.Resume() was broken. But I fixed it.

I’ve also noticed that my game throws a bunch of errors on startup (possibly when loading Mono-related libs) that look a little like this:


DLCGame.Mac(3296,0xb0183000) malloc: *** error for object 0x253f1010: pointer being freed was not allocated

*** set a breakpoint in malloc_error_break to debug

I don’t think there’s a <sarcasm> tag powerful enough to say I’m looking forward to figuring that one out.

That’s about it for Day 8. It’s getting to the nitty-gritty and game-specific stuff now. Still haven’t looked at the Mac store requirements… one of these days…

Running total: 8 days, $112.87

The Great Porting Adventure: Day 7

In this episode, our hero does battle with the beasts known as music and vsync… and wins.

Last time, I wrote about how I had successfully transitioned to a SoundEffect-based audio system. This was true, but it was also not the end goal. I was playing my music as a SoundEffect as well, which had the unfortunate requirement of all the source files being in .wav format. This meant that the music in my game was taking up about 170MB of space. Yikes.

There are two ways you deal with this in XNA land: switch to XACT to get fancy xWMA compression (not an option) or use the Song API to load in MP3 or WMA files (which both end up as built WMA files). Simple, right?

So I switched up my audio system to use Songs whenever a music cue was played (and updated the pipeline and content loader accordingly to use Song objects instead of SoundEffects for music cues). Then I remembered some of the drawbacks to the Song API.

You can only have one Song playing at a time, so there’s no way to do cross-fading. What’s more, the Song is controlled through the MediaPlayer class which has ridiculous overhead doing simple things like changing Volume. That means it’s impractical to do fading out manually by adjusting Volume. It’s possible, but you take a big performance hit for something simple (on Xbox anyway).

So I reverted all of those changes and went back to using SoundEffect for music. I realized that you can actually use waves processed with a bit of compression (ADPCM) and still load them as SoundEffect objects. This was great, because it saved something like 70% filesize for “Medium” quality (which sounds fine for the chiptune-style music I have).

Next I had to solve the pesky problem of not being able to play multiple SoundEffectInstances of the same SoundEffect (a limitation of the current build of MonoGame). Fortunately, there is an outstanding pull request on the MonoGame github project that integrates OpenAL support along with a bunch of missing SoundEffect functionality. I had to download and build maccore and monomac from source first, but that was a simple case of cloning those repos and running “make” from inside the monomac folder.

This is a picture of the OpenAL logo, because otherwise this post would be mostly text.

After all that – it didn’t work! Turns out that OpenAL doesn’t seem to support ADPCM wave files, so I’m back to square one as far as music goes.

Or am I? OpenAL can read MP3 files. And the SoundEffect object doesn’t care what’s in its buffer. So I can actually load MP3 files as SoundEffects directly using MonoGame! Vanilla XNA can’t even do that!

I had one more bug where I wasn’t disposing of SoundEffectInstance objects properly (my code), but once that was fixed, everything seemed to be working perfectly. Yay!

Next on the docket was vsync. The screen tearing I was experiencing was unacceptable, so vsync was definitely required. Thankfully, @SoftSavage (the current MonoGame coordinator) pointed me in the right direction with some docs from Apple on the subject. It was a simple case of finding out where to get the OpenGLContext and then set up the SwapInterval. Since I had just built monomac from source, this was relatively easy to track down and then add it to Game.applyChanges() thusly (line 19):

internal void applyChanges()
{
    if (GraphicsDevice.PresentationParameters.IsFullScreen)
        _platform.EnterFullScreen();
    else
        _platform.ExitFullScreen();

    // FIXME: Is this the correct/best way to set the viewport? There
    // are/were several snippets like this through the project.
    var viewport = new Viewport();

    viewport.X = 0;
    viewport.Y = 0;
    viewport.Width = GraphicsDevice.PresentationParameters.BackBufferWidth;
    viewport.Height = GraphicsDevice.PresentationParameters.BackBufferHeight;

    GraphicsDevice.Viewport = viewport;

    _platform.Window.OpenGLContext.SwapInterval = graphicsDeviceManager.SynchronizeWithVerticalRetrace;
}

There was a bit of other housekeeping to get the above code to work, so I include that only to show you the general idea. There is one other odd and important thing thing: in monomac, the MonoMacGameView class (parent of the GameWindow your game runs in) looks like this:

public void Run (double updatesPerSecond)
{
    AssertValid ();
    if (updatesPerSecond == 0.0) {
        Run ();
        return;
    }

    OnLoad (EventArgs.Empty);

    // Here we set these to false for now and let the main logic continue
    // in the future we may open up these properties to the public
    SwapInterval = false;
    DisplaylinkSupported = false;

    // Synchronize buffer swaps with vertical refresh rate
    openGLContext.SwapInterval = SwapInterval;

    if (displayLinkSupported)
        SetupDisplayLink ();

        StartAnimation (updatesPerSecond);
    }

You can see that vsync will be disabled no matter what you do (line 13). Fortunately, this only occurs just before the first Update. It does mean that you have to setup vsync after your Game has called Initialize(). I just added the following to MacGamePlatform.StartRunLoop():


public override void StartRunLoop()
{
    _gameWindow.Run(1 / Game.TargetElapsedTime.TotalSeconds);

    //The first call to MonoMacGameView.Run disables vsync for some reason, so  give
    //the game a chance to re-enable it here
    this.Game.applyChanges();
}

And then everything was right as rain.

The game is really coming together now. I gave the app packager/installer a whirl too and that looks pretty straightforward, which is a breath of fresh air compared to making an installer on Windows. More work remains to be done key binds, controller support, my loading screens and some resolution/alt-tab support, but I’m getting close! Oh, and I suppose I’ll need to look into Mac Store requirements sooner rather than later too :)

Running total: 7 days, $112.87

The Great Porting Adventure: Day 6

Day 5 ended with me realizing that an XACT-based audio system was probably going to be a bit of a bust using MonoGame. Sure, I had gotten the very basic “play a sound” functionality to work, but all the features I make use of in XACT are not likely to show up in the near future.

Speaking of which, I was asked why I use XACT at all. My main reason for trying it was its handling of music. XACT gives you nice crossfade options, as well as Category support (which in turn grants you Custom Soundtrack support on Xbox for free). It also gives you a nice layer of abstraction between sounds and the waves they use, meaning I can tweak the underlying sound of the game without changing anything in code. These sounds can also have nifty features like distance attenuation, instance limiting and automatic volume/pitch variance for giving your audio a bit of randomness. All of this is managed in reasonable functional application that allows me to keep my audio content separate from the game. To add new sounds (cues), I just update the XACT project and then call the corresponding cue from within code. I don’t need to update my game’s content project or loading, since it’s all handled through the “.xap” asset (which builds the associated wavebanks and soundbanks).

So XACT is great and now I can’t use it. But you can’t use it on Windows Phone either, so really it’s just Windows and Xbox. Maybe moving away from XACT is a prudent move, especially if I can get the same functionality out of SoundEffect.

It was time for a musical interlude!

Disclaimer: This is basically unnecessary over-engineering that I did for the heck of it. Don’t think for a second that this is required for porting to MonoGame, though it is part of my approach to porting.

I already added a layer of indirection to my audio system, so now it looked a little like this:

Pseudo-UML. Thanks Word art!

Coming up with an equivalent SoundEffect-based implementation was relatively straightforward, given that the features I use in XACT aren’t that advanced. I had to do a bit of work to keep track of instances (in categories) as well as music cross-fading, but it was all pretty simple to do. And my game didn’t need to change at all (other than to say whether it wanted to use XACT or SoundEffect).

The big wrinkle was how I was going to tell my game what sounds to load and what sort of features they would have (Category, volume/pitch variance, cue names rather than file names). After all, I want to just be able to play a sound by its cue name from the game, regardless of what the audio implementation is underneath.

One of the overarching goals of this whole project is to avoid maintaining different versions of anything just for the sake of porting. “Write once, play everywhere” right? If I need to maintain a separate list of sound effects to load (or have to add them to my project manually), it’s going to get out of sync quickly and be a huge headache.

But I already have a description of all the waves, cues, categories and events: the .xap file.

Here’s a peek at a small part of the .xap file for DLC Quest:


Category
{
    Name = Music;
    Public = 1;
    Background Music = 1;
    Volume = -260;

    Category Entry
    {
        Name = Global;
    }

    Instance Limit
    {
        Max Instances = 1;
        Behavior = 2;

       Crossfade
       {
           Fade In = 2000;
           Fade Out = 2000;
           Crossfade Type = 1;
       }
    }
}

Aha! A plain-text description of all the meta-data I’d need to play my sounds! Not in an easily paresable format though. It looked simple enough that I was going to try writing a quick and dirty parser. Then I found XapParse. From the Codeplex page:

A C#-based XACT project (XAP) file parser, intended for use as part of the custom content pipeline in XNA.

Hot dog, just what I needed! Here was the plan:

Add a new SoundEffectMetaData class to my audio system. Whenever a cue needs to be played by the SoundEffect-based system, it looks up the associated meta data and uses that to play the appropriate wave with the correct category/volume variance/pitch variance, etc.

Create a XAP Pipeline Extension project to:

  1. Read in the .xap file.
  2. Parse the .xap file into objects using the xapparse project.
  3. Construct a list of SoundEffectMetaData objects from the in-memory representation of the XAP project in Step 2.
  4. Write out the list of meta data to an .xnb file (automatic .xnb serialization is awesome – no work here!)
  5. Also, call context.BuildAsset to find and build the corresponding .wav file.

Step 5 is important, because it means that I can just build the .xap file and it will build all the required wave assets without me needing to add them to my content project.

Lastly, in my game itself:

  1. Reference the XAP Pipeline Extension in the Content project.
  2. Switch the Importer/Processor on the .xap file to use my new extensions and build.
  3. Copy the built list of metadata and all the built sounds to the Mac project.
  4. Switch the Importer/Processor back to the default XACT project to continue using it with the Windows/Xbox builds.

Step 4 here is simply because all content builds are performed on Windows and I need to build things a different way for Mac. I still need to come up with a nicer way of syncing content to my Mac build, but for now I can just switch the processor and I get everything I need for the SoundEffect-based implementation.

So now I can continue to manage all my audio inside XACT but still end up with the metadata I need for using SoundEffect when I choose. No duplicating effort, no managing two lists of sounds and their properties. Pretty slick, if a bit convoluted. But that’s why we program, right? :)


This is running a bit long, so I’ll take a quick look at what remains to be done:

  • Handle music properly. Right now it’s just a normal .wav SoundEffect, so the filesize is huge. Should probably be using the Song API.
  • Fix multiple sound effect instances (currently bugged in MonoGame, but there’s a promising pull request for OpenAL support that I’ll try out)
  • Fix vsync (still no idea where to start)
  • Investigate key binds
  • Investigate controller support
  • Bring back my loading screen
  • Supported resolutions list
  • Alt-tabbing? Minimizing? Losing focus? Etc.
  • App bundling
  • Test test test

Not going to finish within 7 days, but the game is looking pretty good right now.

Running total: 6 days, $112.87

The Great Porting Adventure: Day 5

Shorter update today, as I didn’t spend as much time working on the port yesterday. Things are still coming along, but I’m not there yet.

First off, I did a bit of testing to see what was already working. It seems like everything around saving and loading is functional, making use of the user directory seamlessly. Switching to full-screen also seems to Just Work, though I bet the Alt-Tab equivalent on Mac will need some handling. The list of supported resolutions isn’t being populated, so I’ll need to address that eventually. My use of render targets to perform a screen swirl effect also works nicely. I was initially surprised, but then I remembered that I use render targets for drawing anything in my game (to handle resolution-scaling easily), so it was clearly working already.

I then decided to track down the “jitter” that was occurring in my physics. The player character would constantly be moving slightly above ground and then landing, causing a sound and a puff of smoke several times a second. The likely culprit was my newly added handling in the physics manager’s step function that was chewing through updates in increments of 1/60f. It turned out that some rounding was causing updates of 1/60f followed immediately by another update with a very tiny time delta to pick up the remaining time in the frame. Evidently the frame time being passed in was just slightly larger than 1/60f. This tiny extra update wasn’t enough for the player to “fall” all the way to the ground, so his flags were updated to say he was off the ground and hence he would “land” the next frame. Ugly! But also an easy fix (and my fault – nothing to do with MonoGame).

Next up was VSync. I use vsync, but it wasn’t taking effect on the port. It turns out that vsync is just not implemented in MonoGame yet. I’m not sure how that’s an option for anybody – the screen tearing is horrible without it in my game. I spent a little while searching through the code and reading up on vsync in OpenGL and OpenTK, but it’s a problem I don’t actually know how to solve yet. I’ll dig into the Update/Draw/Present loop today I think – my game is probably pegging the CPU at 100% now anyway.

The next glaring issue I tackled is shown below:

I have around 99 problems and one of them is texture filtering.

Something was going a bit wrong with the way my textured tiles were being drawn, but only when the camera was in certain positions. I use Point (or NEAREST in OpenGL terms) texture filtering, so being “a little bit off” on texture coordinates causes the completely wrong pixel to be drawn. The pixels that are drawn are a consequence of the spritesheet I use – you’re just seeing the nearest adjacent pixel (which belongs to another tile type).

After ensuring that the correct sampling and filtering was being used, I used a debugger to verify that my vertices were being sent to the device with the correct texture coordinates. They all seemed correct, but they were also right on the boundary of the… texel (I think that’s the term I want) that I wanted to use. It seemed like occasionally the Nearest filter would pick the pixel just slightly to the left of the coordinate rather than the one just slightly to the right. It feels like I need a half-texel offset or something so that I would be sampling in the middle of the texel rather than the boundary. Regardless, it’s a bit beyond my understanding and the hacky fix was just to add a tiny constant offset to the texture coordinate, which did the trick. Sometimes the “right” fix is the one that works.

Now that the game looks more or less correct (minus vsync) and plays properly, I decided it was time to see just how broken XACT under MonoGame really was. I had seen this video showing an AppHub sample running with XACT sound on MonoGame, so I knew there was a least some potential. The first roadblock was that xWMA files are not supported. I use this for my music, as it saves me something like 95% filesize versus PCM. For giggles, I rebuilt my XACT project using all PCM format (for a nice 20x increase in filesize) and loaded it up. I spent another while figuring out that other things are not supported, such as using Volume/Pitch Variance and RPCs like DistanceAttenuation. Categories are also missing. Those are pretty much my main reasons for using XACT in the first place.

What’s more, the reading of XACT soundbanks/wavebanks is essentially black magic. None of the file format is documented, so the whole thing is a lot of guess work and tedious file analysis. It took a fair amount of work just to safely ignore the unsupported features I was using in order to have the basic sound effects work. I don’t see myself reverse engineering the binary format to get those features working.

To that end, I’ve decided to give the SoundEffect approach a shot. Taking a page out of computer science’s handbook, I added another layer of indirection to my audio system and can now swap out the XACT implementation for a SoundEffect-based implementation without my game being any wiser. But I still want to retain some of the nifty features, like volume/pitch variance. And I don’t want to have to maintain a separate list of .wavs to load. Fortunately, it looks like the .xap file for an XACT project contains a human-readable description of all the waves, sounds and cues in the project. If can process that at build time to generate some SoundEffect wrapper objects… hmmm… a new project for today.

That’s where things stand for now. I’m going to continue working at a replacement audio implementation. I’m also going to look into vsync – if anyone has any experience here, I’d love to hear from you.

Running total: 5 days, $112.87

The Great Porting Adventure: Day 4

Here be dragons

Back to work after a weekend off. I’ve started to get some good feedback from other devs who are curious about the porting process. It’s great to see some on Twitter deciding to give it a whirl too – it’s always easier when you have more eyes on something. It seems like most are content to follow along and see what happens first. Honestly, that’s a pretty smart approach since I have no idea if this is going to work in the end.

So, day four. This was easily the worst day so far.

At the end of day three, I had my game all converted and compiling, but anything beyond my first screen wasn’t drawing properly. In fact, it was initially crashing trying to apply a texture that was never set (and never needed to be applied anyway). I put a quick guard against using such a null texture to get things running, but it quickly became obvious that things were Not Right.

Specifically, everything except my menus and the background was not being drawn at all. It looked a bit like this:

You could technically play the game using the brown pixels under the "Y" in top left.

Upon (very) close inspection, I could see some tiny moving dots in the upper left corner of the screen. It seemed like anything I was drawing with just a vanilla “SpriteBatch.Draw()” call was working, but the rest of my game was tiny and offset. All of those draw calls used a more involved Draw override that included a SpriteSortMode as well as a BasicEffect argument. Now I had to figure out why those calls weren’t doing what I expected.

This is where I spent most of my day. Stepping through the MonoGame framework, trying to figure out what it was doing and then trying to figure out what it should be doing instead. This isn’t easy when you don’t know what “right” looks like.

Armed with Reflector and the StockEffects sample from AppHub, I dug through the internals of XNA’s SpriteBatch, BasicEffect and its associated shaders. MonoGame is not the line-for-line port of XNA that I expected. I’m guessing that’s for for legal reasons, but maybe it’s for technical reasons. I don’t know. I do know that the implementation MonoGame uses is incomplete though. This makes sense, since only 2D is supported at the moment whilst BasicEffect has a lot of 3D features.

Eventually, I found this in MonoGame’s implementation of one of BasicEffect’s vertex shaders:


gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

This was the first “Aha!” moment. Setting World/View/Projection on the BasicEffect modifies shader parameters, not built-in GLSL uniforms (by the way, did I mention I had to read up on OpenGL and GLSL?). This is why setting my own values had no effect! I therefore changed it to this:


gl_Position = gl_Vertex * WorldViewProj;

In the above, “WorldViewProj” is a uniform that is set by BasicEffect. Note that the order of multiplication is switched because matrices in XNA are row-major, whereas OpenGL uses the column-major convention. I think.

Compile, run….

No change.

Since I don’t really know what I’m doing, I played around with various different matrix values and shaders for a while with no luck. I would receive runtime errors whenever the shaders failed to compile or link, so I foolishly assumed they were working. I began to suspect something was seriously wrong when I modified the pixel shader to just return the color red and yet the textures were still drawn. Something was definitely not behaving as I expected. Whenever problems like this come up in the AppHub forums, the answer is invariably, “Have you tried PIX?”. I should look into some sort of PIX alternative – it would have saved me a lot of time.

It took a lot of investigation, stepping through code, and reading up on OpenGL to determine that although the shader program was being constructed, compiled, linked, set, etc properly, it was also subsequently being unset just before the actual draw OpenGL call happened. Argh! I used the following call to inspect what shader program was active in order to figure that out:


GL.GetInteger(GetPName.CurrentProgram, out programNum)

Since “programNum” came back zero, I knew OpenGL was using the fixed function pipeline and not BasicEffect’s shaders. It was easy enough to track down where the erroneous call to GL.UseProgam(0) was and resolve that.

With the shaders now actually being used, I was able to work my way back from “all red pixel shader” to a properly functioning BasicEffect, complete with World/View/Projection matrices. Drumroll…

DLC Quest on a Mac! Now with actual gameplay!

Yay! In-game!

That’s actually skipping ahead a bit, but I figured you deserved a picture after all that rendering rambling.

I had to do a bit more work to enable SpriteBatch tinting, but that was rendering solved for today. There were a few more issues though.

First off, a lot of my data (awardments, DLC pack definitions, etc) was not being loaded at all. It turned out to be my use of the ContentManifest, which is a sample from the AppHub. In a nutshell, the ContentManifest is an asset that builds a list of all the assets in your Content project at build time. The result is a list of filenames that you can read at runtime to iterate through the built files. I use this to facilitate a data-driven approach to things like awardments – I just drop an awardment .xml file in my content project and it will be loaded by the AwardmentManager automagically.

However, since all content is built on Windows, those filenames use the Windows file separator (“\”). When I read them at runtime on a Mac, they still have the (now incorrect) Windows separator and thus parsing them using something like Path.GetDirectoryName doesn’t work. I added a little fixup routine for the slashes and that was that.

The last problem was that everything was falling through the world.

This came as a bit of a surprise. How could that be platform dependent? Maybe a floating point precision difference? I was perplexed, and certainly not looking forward to debugging my core collision library.

I disabled gravity and glided my character around the world, only to find that collision worked just fine against vertical surfaces. I then added a toggle to gravity so I could turn it back on at runtime easily, which let me run and jump properly, but only if gravity was initially disabled. That was a hint that something was going wrong on the first frame.

Turns out that my physics step function took a “float deltaTime”, but made no checks that the delta was a reasonable duration. The first frame of my game was unusually long on Mac and thus all of the objects were simply tunneling through the ground on the first update. Whoopsie. I updated the function to chew through multiples of 1/60 sec rather than just whatever the deltaTime was and then things were back to normal.


This has been a super long update, but it was a long and frustrating day for the most part. Being able to run around my game and interact with things is a great reward though, so I’m thoroughly motivated to press on. There’s still a lot to do though. There seems to be some precision problem with collision after all, as entities are a bit jittery on the ground. Audio is still missing. I haven’t even tried the part of my game that uses render targets. Controller support is untested. Keybinding is an unknown. The list goes on.

And yet, I’m happy with my progress :)

Stepping outside your programmer comfort zone is how you become a better programmer. I’ve definitely got that first bit down.

Running total: 4 days, $112.87

The Great Porting Adventure: Day 3 Recap

The way I was numbering these posts felt a bit weird, since the “Day 3″ post was a recap of Day 2 plus my plan for that day. I’ll use this post to get back on track, and also because I probably won’t be doing any work today so calling it Day 4 would just be silly.

So my plan was to come up with an automated way of creating and setting up the MonoMac copies of solutions and projects, but given that I didn’t really know what was happening, I figured it would be prudent to try porting over a few more projects manually. Looking into the .sln and .csproj format, I decided it might just be faster to do it all manually this time around. I’d certainly like to take a stab at making a tool to do this at some point in the future though.

  1. Started porting over my “DebugUtil” library, which I figured was pretty straightforward and self-contained. I quickly realized that it relied on my “Core” library, which in turn relied on EasyStorage. So much for minimizing dependencies.
  2. Started porting over EasyStorage. To my surprise, this was relatively painless. There was a bit of a discrepancy in the implementation of IUpdateable and IDrawable in MonoGame (its eventhandlers were just EventHandler, not EventHandler<EventArgs>) but that was simple enough to fix. Not sure if that was the right way to fix it, but it compiled and the sample ran fine nonetheless. There also seems to be a difference in the way .resx strings are handled, but I just ignored all of that and kept only English support for the time being. None of my games are localized anyway, so I’ll fight that battle another day.
  3. Lunch!
  4. Then it was time to tackle some of my own libraries, including my debug utilities, my “core” library (with things like input, audio and storage) and my “tweaker menu” lib, for messing with tagged values at runtime. Audio support with XACT is kinda spotty/missing with MonoGame, so I just compiled out audio for now. That was a fight I knew I’d be making going into this, so I plan on dealing with it after the rest of the game is working.
  5. Next came TiledLib. This should have been straightforward, but the support for ExternalReference in the ContentReader implementation in MonoGame was a bit broken. Specifically, the path it pieced together for external assets was incorrect. I played around with it a bit and got it to construct the proper path.

    Why hello to you too, TiledLib sample.

  6. With all my dependencies now converted, and some of them tested, it was time to move on to the main event and start porting DLC Quest.
  7. Only a few compilation errors off the bat, including one for a missing GameTime constructor. Easy enough to implement myself, but a strange omission.
  8. I then came to realize how often I use “#if WINDOWS” in my code. A whole lot of “|| MAC” was added.
  9. I compiled out Audio, my keybind input hooks and my whole “draw from a different thread while loading content on the main thread” just to simplify things. I’ll tackle these soon, but for now audio has some missing XACT support, my input hooks rely on Windows functionality, and creating a SpriteBatch on a different thread seems to cause an OpenGL shader crash.
  10. Et voila!

    DLC Quest, on a Mac. But not really.

But wait! Why did I choose a screenshot of the intro screen and not gameplay? Well, there’s still a lot of work to be done. Something in my main game’s spritebatch calls, be it the SpriteSortMode.Deferred or the use of a custom BasicEffect, causes a crash in MonoGame. I haven’t looked into it enough yet to say what the cause is.

Still, mighty fine progress for two days worth of work in MonoGame (plus one day for investigating porting options)! Nothing more for today though – time to go play some games with friends.

Running total: 3 days, $112.87

The Great Porting Adventure: Day 3

Yesterday was spent in Mac land, which is an unfamiliar and glossy place. Fortunately I found a nice set of blog posts to guide me on my quest. If you want a tutorial, go read those posts. If you want to see what happens when someone tries to go from zero to Mac port, read on.

Here’s a recap of my experience. This is more for my own benefit rather than a tutorial for others, though it may give you an idea of what’s involved.

  1. Download XCode 4.2 for Lion, MonoDevelop and the MonoFramework.
  2. Watch some videos on how Macs work (seriously) and set up a user account for myself since my Mac is borrowed.
  3. Try to install xcode. Discovered that my version of OSX is Snow Leopard, not Lion and thus I have downloaded the wrong version. But the version for Snow Leopard is only available for paid Mac or iOS developers! I need to either upgrade to Lion or purchase a Mac/iOS developer membership in order to get xcode for Snow Leopard.

    This cat is too old.

  4. Decide I’ll need it eventually anyway and purchase a Mac Developer account for $99 + tax.
  5. Lunch!
  6. Purchasing doesn’t grant access immediately, but I receive my activation within about an hour.
  7. Download XCode 4.2 for Snow Leopard this time!
  8. Download and set up Git
  9. Fork and clone MonoGame. It’s still under very active development, so I choose to fork rather than just download a copy. Maybe I’ll be able to contribute!
  10. Install Mono itself (which is the analog to the .NET framework SDK in my head)
  11. Install MonoDevelop (IDE analog to Visual Studio)
  12. Don’t install MonoMac Add-in for MonoDevelop, because it appears to already be installed!
  13. Download MonoMac samples for playing with later from Github
  14. Download MonoGame samples for playing with later from Github
  15. Build some of the MonoMac samples and play with them. No problems there! That’s .NET on a Mac then. Easy peasy!
  16. Build some of the MonoGame samples and play with them. Some strange changes are needed in order to make them work, but nothing too absurd. XNA on a Mac! Easyish peasyish!

    PerPixelCollision sample, running on a MacBook. Nifty.

  17. Running an already ported sample is nice, but it’s time to try my hand at porting something “from scratch”. My target is the SpriteSheetSample, which is a relatively small and simple set of projects for a Content Processor, a runtime class and a sample game putting it all together. Should be easy! Roughly:
    1. Create a new solution file
    2. Add in the existing MonoGame framework and Lidgren projects, ensuring the former properly references the latter.
    3. Create new MonoMac projects for the SpriteSheet (runtime library) and SpriteSheetSample (sample game) projects. Make sure they reference MonoGame.
    4. Add some compiler defines like MONO and MAC so I can conditionally compile everything and only keep one copy of the files
    5. Set up the new Program.cs to launch the game the Mac way
    6. Copy over the already-built .xnb files from my Windows machine (I don’t keep these in source control)

    This is a bigger hassle than it sounds. I need an automated solution (“Create Copy for Mac”).

  18. Build and run! Doesn’t work. Or even crash.
    Eventually discover the “Application Output” window and see “Unable to load nib file MainMenu”. Turns out I’ve missed one of the steps in the tutorial and didn’t add an empty interface called MainMenu. This is one of those strange things I was talking about earlier.
  19. I use Mercurial for my projects, so update .hgignore to include:
    - *.DS_Store
    - *.pidb
    This is another thing to automate.
  20. Compiles! Yay! Runtime error! Boo! It’s an error drawing the spritesheet. Looks like the SpriteSheet object is non-null, but fields are null. WTF? Clearly something went wrong during the content load.
  21. Crisis! The debugger does not work! Stepping through code highlights nonsensical lines like comments and destructors when the callstack clearly shows otherwise. This is not workable at all. After restarting and googling the debugger problem, I come up empty.
  22. I decide to check if I can solve the content load problem itself. After some more googling, I find some misleading info about a lack of ExternalReference support in the ContentManager of MonoGame. This eventually proves to be a red herring and is a lesson in making sure your tools work so that you can properly identify the true problem.
  23. Eventually, I manually clean all the projects in my solution (the “Clean All” command was/is failing) and the debugger resumes working. Victory!
  24. From here, it’s a straightforward case of stepping through the content load methods. I discover that non-public fields are not being populated even when marked with the [ContentSerializer] attribute. Easy fix!
  25. Victory!

    It's a cat! And a spritesheet.

  26. With everything in place and working, I push my changes to my repository.
  27. Then I pull them down to Windows machine and check that everything still works.
  28. Everything still works. Done!

A little bumpy, a bunch of rough edges, but I ported something written in XNA to the Mac. What’s more, I kept it in one set of files, so it’s essentially the same as working with a copy for Xbox 360. There are definitely some opportunities to streamline the workflow though.

So the next steps are:

  1. Port another small library/sample to get the hang of what needs to be added/changed/reference/etc in a Mac copy of a project.
  2. Devise some way of automating this part of the process. Maybe.
  3. Come up with a good solution for keeping content in sync for Mac builds. I’m find with building everything on my Windows machine, but I don’t want built content in source control. It would work if I was using something like Perforce, but Hg (or Git for that matter) just isn’t suited to the task. Perhaps a simple rsync script. Moving forward, maybe a Dropbox solution.
  4. Find a desktop layout that works. As in, my physical desktop. Working on Macbook is uncomfortable, especially when it’s in front of my PC’s monitors.

For giggles, I’m going to try to keep a running total of time and money invested in this little adventure.

Running total: 2 days, $112.87

The Great Porting Adventure: Day 2

Where's the Start Menu on this thing?

Yesterday, I spent a chunk of time looking into various possibilities for porting my XNA-based game to non-Microsoft platforms like iOS and OSX. In the end, it seemed like learning Unity would be a prudent move and now would be a logical time to start that process.

In true indie fashion, I’m calling an audible.

I wrote off MonoGame rather quickly without much justification, other than saying it felt too much like magic and I would have trouble resolving any roadblocks I encountered. While that may be true, I think the benefits outweigh the small price of experimentation.The biggest potential upside, other than reusing 95% of my codebase, is that I can maintain a single copy of the game moving forward.

After all, if the MonoGame solution works I should be able to get my game running on something like OSX in a very short time. I figure that’s worth trying out. I’ll spend today setting up my borrowed MacBook, getting my environment in order and running through some MonoGame examples. I figure the OSX port will be a good first test, since it will play identically to the Windows version.

Maybe the first 99% of porting with MonoGame will go smoothly. Maybe the last 1% will prove impractical or impossible. Let’s find out.

Meta-Platforming

There comes a time in every XBLIG developer’s life when they ask themselves, “How can I put this”

“onto one of these?”

This year, I want to hit more platforms than just the Xbox LIVE Indie Games market. My first priority is PC, specifically Windows. In this context, XNA is fantastic. I basically get a Windows build of my games for very little effort (some resolution management and key binding support). But what about OSX and Linux? The Humble Bundle (and the feedback I’ve received) has shown that these are non-trivial segments of gamers.

And then there’s mobile. Even I own a smart phone now, so that means pretty much everybody has one.

So if I’m going to go through the trouble of porting, I figure I might as well shoot for the stars and try to hit as many platforms as possible.

Of course, XNA doesn’t “just work” on these platforms. Porting XNA games has been done before by developers like Radian Games (Super Crossfire) and Fun Infused Games (Hypership Out of Control iOS), so it’s not completely foreign territory. Here’s a quick look at my current thinking:

Goal: Port DLC Quest to as many of the following as possible: iOS, OSX, Android, Linux

Approach #1: Native iOS Port

Rewrite the game from scratch for iOS.

  • Pros:
    • Free (other than iOS publishing fee, but all approaches will include this)
    • Potential for good/great performance, as this is as close to the metal as I can get
    • Learn a lot
  • Cons:
    • Most work. Total rewrite.
    • Have to learn Objective-C
    • Doesn’t directly allow for publishing on Android or Linux
    • Not sure how to port to OSX either

Thoughts: This is the most work, to hit only some platforms. But there’s no “magic” – I would know how everything works.

Approach #2: Port to Cocos2D or similar engine

Rewrite the game using Cocos2D as a base.

  • Pros:
    • Free
    • Save considerable time rewriting engine
    • Works on iOS and OSX
  • Cons:
    • Have to learn Cocos2D engine
    • Still have to rewrite game in Objective-C
    • Still does not directly publish to Android or Linux

Thoughts: Similar to above, but cuts out considerable engine work. But I already have an engine anyway.

Approach #3: Convert using ExEn, MonoGame, etc.

Use a MonoTouch based library/framework to do the heavy lifting and keep my codebase mostly intact.

  • Pros:
    • Use existing codebase, kinda (game needs adapting for touch devices/screens anyway)
    • Might be easier to maintain multiple versions in one solution
    • Write in C#
  • Cons:
    • $400 for MonoTouch (and an additional $400 for Mono for Android)
    • Does not directly publish to OSX orLinux
      • Whoops, apparently OSX is supported. Wizorb also managed a Linux version, so that’s a ‘maybe’.
    • Likely won’t work perfectly, require learning how MonoGame works to fix it

Thoughts: This feels like a magic bullet approach. I’m wary of things not working perfectly and then having to grapple with an unknown technology to try to fix it.

Approach #4: Unity

Re-write the game with Unity and reap the multiplatform benefits.

  • Pros:
    • Write once, hit iOS, Mac, Android, Flash. Possibly even Linux soon.
    • Get experience with Unity, which seems like a sensible business choice
    • Write in C#
    • Can potentially reuse some code
  • Cons:
    • Need to rewrite at least some of the game
    • $400 each for iOS and Android publishing. Potentially $1500 for Unity Pro + $1500/iOS/Android if needed.
    • Large learning curve for the “Unity way” of doing things
    • Likely have to invest in SpriteManager or similar library
    • Basically magic

Thoughts: Unity seems to make the most sense, but I’m also reluctant to use it because it feels like I give up too much control.

And the winner is…

Looking at this (and having slept on it), it seems like all signs point to Unity as the way forward. I’m not a big fan of the “magic” involved with Unity but that’s likely largely attributable to a lack of understanding. I’ll give it a shot and see if my reluctance is warranted or not.

I think the last time I used a Mac for more than 5 minutes was with an iMac in computer class over a decade ago. This oughta be interesting.

You said it dog.

Going Loud Studios: 2011 Indie Dev in Review

Well, that’s 2011 finished. This marks the end of Going Loud Studios first full calendar year of business, so I feel it’s time to take a glance back before moving on.

2011 Review

The Games

I released two new games in 2011:

Lair of the Evildoer (June 2011):

DLC Quest (November 2011):

Both games were picks for “Kotaku’s Favorites” list on the dashboard, which was sweet.

Zombie Accountant WP7 goes free

It might also be worth noting that the Windows Phone 7 version of Zombie Accountant quietly (very quietly) had its price slashed from $1 to $0 in… July? To be honest, I did this just to see what would happen – the game was long dead anyway. I kinda forgot to follow up on it though, so here are the stats:

The Awards

Frankly, I think it’s awesome that I even have anything to write here. DLC Quest won Official Xbox Magazine’s Indie Game of the Year 2011.

Social

I’ve been making indie games for over a year now but I only looked into my city’s “indie scene” in the past few months. Turns out, it does exist! I started attending the monthly meetups put on by the fine folks at Dirty Rectangles which has been a ton of fun. Locking myself in a room to make games has been reasonably successful, but it’s great to meet new people and talk about making games in person. I look forward to doing that a lot more this year.

Sales

Or, “Why you came here”. Here are some stats!

Quick analysis: pretty acceptable! Granted, it’s pretty much all on the back of DLC Quest at the end of the year, but I’m okay with that. Not taking a loss on the first year of business? Sounds good to me.

Presence

Interviews! Podcasts! Print coverage! Youtube views! Twitter subscribers! 2011 was a great year for establishing myself on the internet. A few highlights include having some featured blogs at Gamasutra, coverage at big sites like Kotaku, Game Informer and Games Radar, a brief spot on Attack of the Show on national freakin’ television, participating in a few podcasts, and numerous interviews, including one in print in the January 2012 issue of OXM. I made some great contacts along the way too. The Going Loud Studios Twitter account (@WeAreGoingLoud) and Facebook page have also seen a nice bit of growth, sitting at 410 and 156 followers respectively. Oh, and the trailer for DLC Quest has racked up over 31K views so far.

So not quite famous, but it’s a nice start :)

Looking Ahead

We’re already three days into 2012, so enough with the retrospective! Here’s a quick look at some thoughts for the upcoming year.

More games

This is a no-brainer. Everything above comes from making fun games that I want to play. That’s the driving force that has gotten me here and it’s the passion to continue making games that will take me forward. I’m itching to make something new right now!

More platforms

If you study the releases above carefully, you’ll notice that 100% of all games I published in 2011 were for XBLIG. That’s a market that has its fair share of problems and has a bit of murky future. Even without that, it just makes sense to spread my games to more places where people can play them. PC is my prime target – heck, I have PC ports of both 2011 releases essentially ready to go. 2012 will be the year when I start publishing beyond the Xbox.

Diversify!

More platforms is great, but I’m thinking of ways to take diversifying a step further by exploring things beyond just making games. Don’t get me wrong, making games will always be first and foremost for me. But there are some complementary things I could be doing to spread myself out. At the moment, I’m thinking along the lines of more blogging and YouTube videos. There are benefits to that kind of exposure that might not directly generate income, but are useful for expanding your contacts, popularity and so forth. I don’t have any concrete plans just yet, but it’s something I’d like to experiment with this year. For science.

Game jam!

Can you believe I’ve never participated in a game jam? Everybody always says you should do that. I’m going to do that.

More learnin’! More seat-of-my-pants adapting!

As always, I plan on continuing ‘being indie’ in the philosophical sense. I picked up some great books on game design and engine architecture over the holidays that will be going to good use. Always learning, always trying new things, and always willing to throw out all of my plans if the need arises.

It’ll be nice to revisit this post a year from now and see how 2012 measured up. Now, follow me on Twitter @benkane!

Follow

Get every new post delivered to your Inbox.