My Reasons for Going Back to XNA

This post covers some of the problems I've had with both MonoGame and XNA, and my reasons for switching back to XNA after making the transition to MonoGame.

Note: I wrote this post before I made the switch to Unity.

This post is going to cover some of the problems I’ve had with both MonoGame and XNA, and my reasons for switching back to XNA after making the transition to MonoGame.

The Back Story

Loder’s Fall started out as a Flash game. I had just learned how to program in ActionScript, and decided to make a game. Shortly after that, I started experimenting with ways to get better performance out of Flash and the AS3 port of Box2D. After discovering XNA, I decided moving to C# would be an easy way to get better performance, and I was right.

Then, I played Terraria and enjoyed the grid-based fluid simulation that game had. I decided my game would be more fun if I could add something like that. After a while, I stumbled upon Eric Jordan’s liquid demo and, with some effort, ported it to C# and XNA.

I always enjoyed blowing stuff up in Worms, so I added destructible terrain and spent some time optimizing the fluid simulation so it would perform well when colliding with massive amounts of fixtures.

Then I thought, “I need some vegetation”, so I added some procedurally generated trees. I thought it would be fun to swing around on trees using the rope gun, so I implemented that… but it felt unrealistic without the tree reacting to the force of the rope pulling on it. After I learned how to do verlet integration, I added a number of distance constraints to the tree limbs in such a way that gave me a semi-realistic tree simulation.

Between the multithreaded fluid simulation, the thousands of constraints in the verlet integrated tree simulation, my procedural texture generation, and the massive amount of Box2D fixtures created to enable destructible terrain, my code base was starting to become more than a trivial side-scroller game.

Then, the news came that XNA wasn’t going to be actively developed anymore. That wasn’t too much of a concern since I had recently heard about MonoGame, which was meant to be a cross-platform, open source implementation of Microsoft’s XNA. Knowing that XNA had a few bugs that weren’t going to be fixed, I decided to go ahead and make the switch to MonoGame.

My Experience with MonoGame

First off, I should say that I have no ill will towards any of the maintainers or contributors of the MonoGame project. From what I have gathered, they are all busy being game developers themselves, and I think it’s great they’re spending time contributing to an open source project that could allow people like me to potentially take advantage of it. On top of that, my experiences are completely anecdotal. People are currently shipping games using MonoGame, so it’s obviously viable for some platforms. However, I would like to talk about some of the problems I’ve had with the framework and the libraries it depends on.

The first problem I had, which is still the most serious, is OpenTK. There’s a bug in OpenTK that doesn’t allow the screen’s resolution to be restored after changing. This means if you switch to a fullscreen resolution in MonoGame that isn’t the same as your desktop’s resolution, your resolution won’t be restored to its original setting when you exit fullscreen. Also, the positioning of the window is wrong when entering fullscreen. I opened a bug report for MonoGame, but lack the knowledge to fix the problem myself. I was able to fix the positioning of the window by modifying the ToggleFullscreen method in OpenTKGameWindow, but fixing the bug in OpenTK is currently out of my reach.

Update (7/26/2013): I was able to fix the bug on in OpenTK on Windows by modifying RefreshDisplayDevices() in WinDisplayDevice.cs. Instead of clearing and rebuilding the AvailableDevices list every time RefreshDisplayDevices is called, I create a temporary list of all the old devices and compare the device name. If the device name is the same, I use the existing DisplayDevice. Otherwise, I allow a new device to be created:

List<DisplayDevice> currentAvailableDevices = new List<DisplayDevice>(AvailableDevices);
AvailableDevices.Clear();
// ...
while (Functions.EnumDisplayDevices(null, device_count++, dev1, 0))
{
    // ...
    bool deviceAlreadyExists = false;
    for (int i = 0; i < currentAvailableDevices.Count; i++)
    {
        if (dev1.DeviceName == currentAvailableDevices[i].Id.ToString())
        {
            AvailableDevices.Add(currentAvailableDevices[i]);
            deviceAlreadyExists = true;
            break;
        }
    }
    if (deviceAlreadyExists)
        continue;
    // ...
}

Using MonoGame on Linux or Windows 7 currently means that resolution changes and/or fullscreen toggles, under most circumstances, won’t work correctly. I can’t remember the last game I’ve played that wouldn’t allow me to change resolution while playing, so I consider that a deal-breaker.

Right as I was having this problem, a fork of MonoGame came out that abandons OpenTK and uses SDL2 instead. This completely fixed the window management problems for me. Unfortunately for me, the performance on my own machine wasn’t as good as the official MonoGame (nor was the performance of the official MonoGame as good as XNA). Using the SDL2 fork of MonoGame on Windows, I wasn’t able to run the game in 1680×1050 without severe stuttering problems. If I decreased the resolution to 1366×768, I could usually run the game at 60fps (although I would have intermittent stuttering. Sometimes it ran well, other times it didn’t… I wasn’t able to pin down the exact cause of the performance problems). On Linux, the game ran slow enough that it was completely unplayable.

I have to stress again, that this is all anecdotal. I don’t have any benchmarks to prove what I’m saying about the relative performance, so take what I’m saying with a grain of salt. Just to give some context, I’m using an Intel i3-2100, 3.1ghz with 8gb of RAM and a GeForce 9600 GSO. Nothing special, but something that should definitely be capable of running a 2D game at 1680×1050.

On top of the performance problems, every computer I tested my game on had different problems. The first was an older Windows 7 laptop that ran the original XNA version of the game fine (when I was using the Reach profile). MonoGame wouldn’t run at all. It crashed on startup because it couldn’t find an entry point. From what I’ve been able to gather, that’s because the laptop used an older version of OpenGL (2.1). Neither fork of MonoGame worked on this computer.

The 2nd computer I tested my game on was another laptop (HP ProBook 4530s, 8gb RAM) running Windows 7, but newer than the first. It at least opened a window before stalling, but as soon as the resolution was changed (loaded from a settings file), it stalled. I tried my best to narrow down this behavior. Eventually I was able to get the game to run by hard-coding the resolution settings, but for some bizarre reason, loading the settings from a file and then applying the display changes caused the game to stall out with a black screen (although, according to logging, it was actually updating/drawing the game just fine). This behavior existed in both forks of MonoGame. After switching back to XNA, it worked fine.

The 3rd computer was another laptop (Toshiba Satellite L635-S3100) running Windows 7. This computer was able to run the XNA version, and both of the MonoGame forks up until the point where I loaded a level. On my development machine (the i3), by the time a level was loaded the process was using about 90mb of RAM according to the task manager. I know the task manager isn’t the best way to determine how much actual memory is being used, but the Toshiba laptop used about 1.6gb of RAM before stalling out and never loading the level, so there was something very obviously wrong there. I wasn’t able to figure out what the problem was.

I would have posted bug reports for all these problems if I could have spent the time narrowing them down to the exact problems, but given the numerous problems I encountered, I decided to reevaluate my original decision to switch from XNA.

Moving Forward

My options at this point were XNA, MonoGame, MonoGame-SDL2, or just putting the entire game on hiatus until MonoGame matured to the point that it became useable on the platforms I’m targeting.

When I first started this game, I chose XNA because it seemed like the best tool to make a game. I didn’t set out to recreate XNA. I also started using XNA knowing full well that I would only be targeting Windows machines. Given that XNA works well on all the Windows machines I’ve tried it on, and that MonoGame has had different problems on all of those machines, I’ve decided it would be in my interest to switch back to XNA.

I wish MonoGame the best, and maybe once I have more experience I can contribute to the project (technically I already have, but only by moving an #ifdef up a few lines… nothing significant).

I do recommend anyone who is having problems with the window management in the official branch of MonoGame to check out Ethan Lee’s SDL2 fork that I’ve been mentioning.

Hopefully I haven’t offended anyone with this post.