Many months ago I made my first post about this. Basically it described my experiences building a Windows OpenGL version of an updated version of my game Entangled. This let me flesh out any MonoGame or OpenGL-specific issues before working on the iOS port.
In this port I’ll describe what I’ve done to get it up and running on my iPad, and what’s still left to do.
First, there was a little more work to do on the Windows side of things. Eventually MonoGame will allow building content on MacOS; but for now you need to create a blank project in Visual Studio, edit the project file so it builds iOS (details are on the MonoGame site), and link to your content project. This builds the .xnb files for iOS, which are then copied into your Xamarin Studio project on MacOS.
In your game’s content project, you need to switch to using the MonoGame content processors (e.g. MonoGame SpriteFont, MonoGame Effect, MonoGame Texture, etc…). This requires you add a reference to MonoGameContentProcessors.dll in your content project.
On my machine this was located at “C:\Program Files (x86)\MSBuild\MonoGame\v3.0\MonoGameContentProcessors.dll”
Using these content processors, the correct XNB files will be built for your target platform. For OpenGL platforms, this includes functionality that converts HLSL effect files to GLSL.
One caveat here is that the shader parameter names are different in OpenGL. This issue is described here: https://github.com/mono/MonoGame/issues/641 . So right now you’ll need to use conditional compilation symbols to switch to the correct parameter name in your C# code.
The MonoGame Texture content processor lets you specify a Compression Mode, similar to (or in addition to, since both properties exist) the DXT compression available on Windows. The first time I built iOS content files, I was surprised to see that my textures were 23MB instead of 7MB for the Windows versions. Why is this? PVRTC compression has an additional requirement over DXT compression in that it requires textures be square.
I reworked my textures so that they were square (or the big ones, anyway), and got things down to a manageable size again. Unfortunately – as I was later to discover – PVRTC compression is pretty awful, at least for images with transparency.
On MacOS, I have installed Xamarin Studio, XCode, the monogame package for MacOS, and performed all the certificate signing needed to support deployment to i-Devices. I did this a while back, so I don’t remember the troubles I had.
The monogame package is an .mpack which needs to be added into Xamarin Studio using the Install From File button in Xamarin’s Add-in Manager.
My first step was just to get a default sample project built and running in the iPad emulator. Even this wasn’t trivial though. The project references to Lidgren.Network.dll and MonoGame.Framework.dll will be busted. You’ll need to remove them and add the correct ones in.
I don’t know my way around MacOS very well, so this was actually not a trivial task. I could not find these dll’s that were supposedly added when I installed the .mpack file into Xamarin. It is made worse by terrible file dialog browser in Xamarin’s Edit References dialog (I believe this is the GTK file dialog – what an absolute mess).
The dll’s are located here: ~/Library/Application Support/XamarinStudio-4.0/LocalInstall/Addins/MonoDevelop.MonoGame.3.0.1/assemblies/iOS/
There is a place to type in a path in the dialog, but it doesn’t work. So I had to figure out exactly how this mapped to the MacOS file system and finally browse my way there. I’m pretty sure the files weren’t there the first time, and I had to re-install the .mpack file a second time, but I may have been mistaken. Anyway, this is where they’re supposed to be.
Once this was done, building the sample project generated one error. It simply told me to contact support and receive an update. MT9019. I installed the latest Xamarin Studio updates (I hadn’t had the latest version), but that didn’t fix it. Finding a thread on this in the Xamarin forums, the suggestion was to re-install from scratch. That was unfortunate and time consuming, but it did fix the issue in the end.
Now I had a sample project that compiled and ran in the iPad emulator. I did at first get this error: http://stackoverflow.com/questions/12540597/supported-orientations-has-no-common-orientation-with-the-application-and-shoul, but I resolved it by changing the supported orientations in the Info.plist file in the project.
My project exists on an svn server. So I should probably install svn on my Mac and manage it that way. The thing is, the Mac requires the (very large) xnb files that built on my Windows machine – I don’t really want to check in compiled content files to my svn.
So all I’m doing now is sharing out the folder that my project exists in on my Windows machine. I made a fresh project in Xamarin Studio and added links to all those files (including the compiled XNBs). It seems to work, but the server connection dies every so often. I’m not sure if this is Windows’ fault or MacOS’s. Probably Windows. However, when the connection goes down, MacOS kind of grinds to a halt. The Finder stops working. It can be pretty terrible, and sometimes requires me to log out and back in. MacOS definitely does not handle network “hangs” as well as Windows.
I know this isn’t the best solution, but it seemed to be the quickest to get me up and running.
After figuring out Xamarin’s “add files” and “add folders” dialogs (they’re actually quite good), and sorting out a difference in method overload compiler behavior in Mono (vs .net), I was able to get my project building.
Getting it up and running.
Next, I added all my content files (the .xnb files compiled in Windows) under a Content folder in my Xamarin Studio project. I set the build action to “Content”, and they loaded successfully when I ran the game.
Sound played, but nothing was displayed. Just a black screen. After much debugging, I narrowed it down to the creation of a RenderTarget2D with DepthFormat.Depth24. Just creating this render target (never even setting it) would stop all graphics from displaying forever. So apparently render targets with depth buffers are currently broken in MonoGame. This may be fixed in the latest MonoGame sources (I have yet to verify), but is broken in the last official release (3.0.1). Switching this to DepthFormat.None has worked around the problem for now (at the expense of some graphical glitches).
I must admit, I’m a little confused by the display orientation. My game only works in landscape, so I have specified this in the Info.plist file. However, the GraphicsDevice, when created, claims that it’s 768×1024 (despite me asking for 1024×768). The ViewPort is 1024×768 however, and everything seems to work and look ok. I’m not sure if there’s something different I should be doing here.
As for the game actually working, there were a number of problems right off the bat (stuff I couldn’t really have known about building the OpenGL project on Windows).
The PVRTC texture compression used by the graphics chip in the i-devices is terrible (for my uses, anyway). It’s an 8:1 compression ratio, as opposed to DXT5 which is 4:1. And the artifacts aren’t just limited to blockiness:
You’ll note that the PVRTC texture “bleeds” from the opposite end of the texture. I guess it always assumes that the texture wraps? At first I thought I was somehow drawing the texture with a wrapping texture address mode, but this was not the case.
So basically texture compression is pretty much useless for my purposes, which means that my textures will be 4x the size on disk (and in memory) on iOS than they are on Windows. Very unfortunate.
Path names with backslashes in them won’t work, so you’ll need to use forward slashes (which work on Windows too). For example:
It’s likely that the System.IO functions like Path.Combine work properly too.
In XNA, touch events are automatically translated to mouse events. This meant that I only needed to respond to mouse events in order to have my game work on both Windows Desktop and Windows Phone.
One of the first things I noticed when running my game was that I couldn’t click on anything in the iPad simulator! I found out that in MonoGame the automatic translation from touch to mouse events is not done. So I needed to write some wrapper code that converted touch events into the equivalent mouse events.
Another problem I quickly noticed was that some sound effects would not play. It seemed to be a different set of sound effects each time I ran the game. Searching online, I quickly found this thread. It’s a bug with Xamarin Studio (MonoTouch) apparently, but there is a workaround in MonoGame. Unfortunately it’s not in a released version of the MonoGame binaries yet, so I’ll likely have to enlist in the MonoGame source code and build my own iOS MonoGame binaries (which means I’ll be using an “untested” dev version of MonoGame.
Deploying to the device
Once I got things mostly working in the iPad emulator, I decided to try deploying to the device. I activated my Xamarin Studio trial in order to do this.
I did most of the Apple-related device setup a while back (signing certificates and such), so I was curious to see what would happen. Well, my app deployed to the iPad without any difficulty. Unfortunately the debugger couldn’t connect to the running app: “Couldn’t find developer tools for this device (6.1.3). Please ensure you are using a compatible Xcode version and then connect this device to Xcode to install the development support files.”
I started Xcode and clicked on the button that said “Use this device for development” for my iPad. It said that the version of iOS on my iPad is not supported by this installation of the iOS SDK. It didn’t tell me which version of the iOS SDK I had, but it did tell my that my iPad was 6.1.3.
It had been a while since I’d updated my software, and was I worried about this. Mainly I was worried I’d be required to update to something that would require a new version of MacOS. Basically, your i-Device’s OS, the version of the iOS SDK/XCode you have installed, and your version of MacOS all need to be in sync.
Luckily I was just barely able to squeak by here. I updated to XCode 4.6.5, which is the last version that works with OS X Lion, but is still compatible with my 6.1.3 iPad. Whew!
After this, I was able to debug on the device without a hitch.
Notes about Xamarin Studio
Xamarin Studio feels a lot more snappy and responsive than Visual Studio – and this is comparing a MacBook air to a very powerful desktop machine with solid state drives! So good on Xamarin there.
There are a couple of minor annoyances though:
- Debugging iOS stuff is problematic. When you put a breakpoint somewhere and step through the code, it kind of jumps around randomly. It can be hard to follow or figure out what’s going on. This is somewhat understandable since the running code is native code, not IL.
- In the “solution explorer”, you can’t look at the properties box when multiple items are selected. This is mitigated a bit because some of the properties are available in the right-click menu (which does work for multi-select). But for those that aren’t, it can be really slow to change the same property on multiple items.
- Since I’m editing the same files on my PC in Visual Studio, Xamarin can get confused about reloading files. I haven’t lost any data due to it, but it does throw up a lot of warning dialogs with confusing choices, and complains about line endings.
- Xamarin Studio won’t autocomplete enums that are [Flags] once you’ve put a & or | operator in the expression.
Frame rates are terrible in the iPad emulator.
Content size for my game: 17MB on Windows vs 27MB on iOS (mainly due to texture compression not being suitable).
I’ll probably make a follow up post closer to when my game is ready to ship (and hopefully I’ve worked out the audio issues).