F# and Monogame Part 1 – MacOS

I recently did a talk at SkillsMatter on developing on iOS using F#. For the demo I knocked together a small demo called “Pissed Off Owls” to show how easy it was to write a game in F# (my target was ~100LOC).

Originally I wrote the demo using OpenGL – why not? It runs on Windows, Mac, Android, iOS (and more). But then I considered Monogame. It’s a clone of Microsoft’s abandoned XNA, but rather than targeting the devices that XNA supports (Windows Desktop, Xbox 360 and Windows Phone 7) it fills in the (wide) gaps that XNA doesnt support (MacOS, Android, iOS, Windows 8, Windows Phone 8, Ouya, PSP Vita). It’s a nice friendly API and is under active development.

So I’m going to write a short series of posts on how to make Monogame run using F# on various platforms. It’s not a Monogame/XNA tutorial per-se, but a jump start into how to get the 1st window on-screen without having to bootstrap the app using C#.

So, without further ado –

MacOS & Monogame

I’m going to assume you’ve already got Xamarin and the MacOS F# tools installed.

First open Xamarin Studio and create a new “F# Console Application” project.

Add references to Monogame.Framework.dll, Lidgren.Network.dll & Tao.Sdl.dll. I’m going to assume you’ve successfully installed Monogame already.

To instantiate a new Game class you’ll also need to reference MonoMac.dll.

Next navigate to the folder where the F# project lives and open the .fsproj file in TextEdit.

Under the <Import> for the FSharp.targets add the following import

<Import Project="$(MSBuildExtensionsPath)\Mono\MonoMac\v0.0\Mono.MonoMac.targets" />

While you have the .fsproj file open also add the following line under the <ProjectGuid> tag

<ProjectTypeGuids>{948B3504-5B70-4649-8FE4-BDE1FB46EC69};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

Back in Xamarin Studio wait a moment for the solution to reload and you’ll probably now find you cannot run the app! You’ll get a nice error like “No build configuration set for Debug”. You can remedy this by simply opening the project options and closing them again.

Next, let’s write a little code:

Replace the contents of Program.fs with

open System
//Simple version of the XNA Game class. 
//This is the minimal you'll need to see something onscreen
type Game() as game =
    inherit Microsoft.Xna.Framework.Game() 
    let manager = new Microsoft.Xna.Framework.GraphicsDeviceManager(game)

[<EntryPoint>]
let main args = 
    let game = new Game()
    game.Run()
    0

Run this and **bang** –

MonoMac.AppKit.AppKitThreadAccessException: AppKit Consistency error: you are calling a method that can only be invoked from the UI thread.
  at MonoMac.AppKit.NSApplication.EnsureUIThread () [0x00000] in :0
  at MonoMac.AppKit.NSWindow..ctor (RectangleF contentRect, NSWindowStyle aStyle, NSBackingStore bufferingType, Boolean deferCreation) [0x00000] in :0
  at Microsoft.Xna.Framework.MacGameNSWindow..ctor (RectangleF rect, NSWindowStyle style, NSBackingStore backing, Boolean defer) [0x00000] in :0
  at Microsoft.Xna.Framework.MacGamePlatform.InitializeMainWindow () [0x00000] in :0
  at Microsoft.Xna.Framework.MacGamePlatform..ctor (Microsoft.Xna.Framework.Game game) [0x00000] in :0
  at Microsoft.Xna.Framework.GamePlatform.Create (Microsoft.Xna.Framework.Game game) [0x00000] in :0
  at Microsoft.Xna.Framework.Game..ctor () [0x00000] in :0
  at Program+Game..ctor () [0x0000a] in /Users/.../.../TestApp/Program.fs:5
  at Program.main (System.String[] args) [0x00000] in /.../.../TestApp/TestApp/Program.fs:10

Ouch – this is the rough equivalent to the “You’re not calling UI code on the UI thread you fool” Exception on Windows (UnauthorizedAccessException I beleive). The solution is to write a small amount of Cocoa code. Luckily for us, this is nicely trivial in F# and Mono.

Firstly open the following namespaces:

open MonoMac.AppKit
open MonoMac.Foundation

Then replace the main function contents with this:

NSApplication.Init()
use p = new NSAutoreleasePool()
NSApplication.SharedApplication.Delegate <-
    { new NSApplicationDelegate () with
      member x.FinishedLaunching notification =
          let game = new Game()
          game.Run()
      member x.ApplicationShouldTerminateAfterLastWindowClosed _ = true
    }
NSApplication.Main (args)
0

Now run and we don’t get a big nasty exception, but it’s fairly underwhelming:

“No Info.plist file in application bundle or no NSPrincipalClass in the Info.plist file, exiting” will appear in the application output.

Open Info.plist (this should have automagically been created for you already) and in the “Source” tab add a new string property with a key of “NSPrincipalClass” and a value of “NSApplication”.

Run again and you should be able to see a new window full of garbage! Huzzah!
To see something (slightly) more interesting add the following line to your Game class

override __.Draw _ = game.GraphicsDevice.Clear Microsoft.Xna.Framework.Color.CornflowerBlue

And rejoice. You can now start developing Monogame games on MacOS in Xamarin studio purely in F#.

Advertisements

About thedo666

Software developer trying to learn a new language - English!
This entry was posted in F#, Mono, Monogame and tagged , , , . Bookmark the permalink.

5 Responses to F# and Monogame Part 1 – MacOS

  1. Pingback: F# and Monogame Part 2 – Android | Neil Danson's Blog

  2. Pingback: F# Weekly #31 2013 | Sergey Tihon's Blog

  3. Pingback: Xamarin Link Roundup – 6 Aug 2013 | Well Technically…

  4. Pingback: F# and Monogame Part 4 – Content Pipeline | Neil Danson's Blog

  5. Pingback: F# on Android

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s