5

I am experimenting a bit with F# and I am wanted to see if I could do some simple stuff with Monogame in F#. I figured the translation from C# to f# would be straightforward but it has not been so far. The code I have so far is just a simple empty project which should run. Or at least it would in C#. However running this in F# yields a

Unhandled exception. System.InvalidOperationException: No Graphics Device Service

The code I have is this, which really does not do anything crazy. I was forced to use a mutable val for the spritebatch as you must instantiate it in LoadContent for whatever reason. Anyone have any pointers to what I am doing wrong? I would be most grateful.

type GameState = 
    inherit Game
    new() =  { inherit Game(); Sb = null;  }
    member this.Gfx : GraphicsDeviceManager = new GraphicsDeviceManager(this)
    val mutable Sb : SpriteBatch 

    override this.Initialize() = 
        this.Content.RootDirectory <- "Content"
        this.IsMouseVisible <- false
        base.Initialize ()

    override this.LoadContent () =
        this.Sb <- new SpriteBatch(this.Gfx.GraphicsDevice)
        base.LoadContent ()

    override this.UnloadContent () = 
        base.UnloadContent ()

    override this.Update (gameTime : GameTime) = 
        base.Update (gameTime)

    override this.Draw (gameTime : GameTime) = 
        this.Gfx.GraphicsDevice.Clear (Color.CornflowerBlue)
        this.Sb.Begin()
        //draw here
        this.Sb.End()
        base.Draw (gameTime)

[<EntryPoint>]
let main argv =
    let gs = new GameState()
    gs.Run()
    0 // return an integer exit code
kiooikml
  • 307
  • 1
  • 7
  • 1
    Here `member this.Gfx = new GraphicsDeviceManager(this)` will create a new `GraphicsDeviceManager` every time you access `this.Gfx`. That's probably not good. – Asti Apr 20 '20 at 21:54

1 Answers1

4

Asti is correct, you don't want to create a new GraphicsDeviceManager repeatedly.

Here is some working code with minimal changes to yours. Note that to define values at constructor-time you need the () after the type name. Using mutable for the SpriteBatch is ugly but common in this case, and you don't need to make it a member:

open Microsoft.Xna.Framework
open Microsoft.Xna.Framework.Graphics

type GameState() as this = 
    inherit Game()
    let gfx = new GraphicsDeviceManager(this)
    let mutable sb = Unchecked.defaultof<SpriteBatch>

    override this.Initialize() = 
        this.Content.RootDirectory <- "Content"
        this.IsMouseVisible <- false
        base.Initialize ()

    override this.LoadContent () =
        sb <- new SpriteBatch(gfx.GraphicsDevice)
        base.LoadContent ()

    override this.UnloadContent () = 
        base.UnloadContent ()

    override this.Update (gameTime : GameTime) = 
        base.Update (gameTime)

    override this.Draw (gameTime : GameTime) = 
        gfx.GraphicsDevice.Clear (Color.CornflowerBlue)
        sb.Begin()
        //draw here
        sb.End()
        base.Draw (gameTime)

[<EntryPoint>]
let main argv =
    let gs = new GameState()
    gs.Run()
    0 // 

Feel free to take a look at this repo of mine which gives a working example of using MonoGame with F# (although it's probably a bit out-of-date now), including basic content pipelines.

Mark Pattison
  • 2,964
  • 1
  • 22
  • 42
  • Thank you, F# classes are still extremely confusing for me and just seem very awkward to use. Will check out your repo as well for inspiration! – kiooikml Apr 21 '20 at 21:07
  • No problem. I find that I don't need to uses classes at all most of the time in F#, but obviously MonoGame needs one here. – Mark Pattison Apr 21 '20 at 21:10