Some years ago I played around with XNA. That never really went anywhere and XNA is now dead. So I’m going to be using Monogame.
I’ve created a new console project that I’ve named “View” and I’ve added the Monogame DX Nuget package. I’ve changed the output type to “Windows Application”.
I’m on new ground so I’m following this tutorial using F# and Monogame. This will get me started. My requirements will diverge from the tutorial quickly though.
The first piece is to create the minimum “Game” necessary to open a window
namespace Morgemil.View open Microsoft.Xna.Framework open Microsoft.Xna.Framework.Graphics type GameView() as this = inherit Game() let graphics = new GraphicsDeviceManager(this) override this.Initialize() = base.Initialize() base.Window.Title <- "Morgemil" override this.LoadContent() = () override this.Update(gameTime) = () override this.Draw(gameTime) = this.GraphicsDevice.Clear Color.CornflowerBlue |
There you go! The entire game is done! Time to label it as early access, make more false promises than a politician, and rake in the cash.
I’ll do that next time. Right now let’s actually make a game. And every game needs a way to draw things. This first prototype will be super basic. No need for actual textures, just draw some colors.
type GameView() as this = inherit Game() let graphics = new GraphicsDeviceManager(this) let mutable spriteBatch = Unchecked.defaultof<SpriteBatch> //null let mutable spriteTexture = Unchecked.defaultof<Texture2D> //null override this.Initialize() = base.Initialize() base.Window.Title <- "Morgemil" override this.LoadContent() = spriteBatch <- new SpriteBatch(this.GraphicsDevice) spriteTexture <- new Texture2D(this.GraphicsDevice, 1, 1) //Only need 1 color spriteTexture.SetData([| Color.White |]) //255,255,255 override this.Update(gameTime) = () override this.Draw(gameTime) = this.GraphicsDevice.Clear Color.Black spriteBatch.Begin() //Draw things here spriteBatch.End() |
The first thing to draw will be the dungeon, which we already have. Colors for the map tiles will be chosen very simply: can the player walk there?
let ChooseColor(tileDef : Morgemil.Map.TileDefinition) = match tileDef.BlocksMovement with | true -> Color.Black | false -> Color.White |
Each tile will take up two pixels square to start with. Notice that the argument “ChooseColor tileDef” in spriteBatch.Draw is not the actual color to draw. It is a mask to be applied to the texture. The texture is pure white (255,255,255). The mask is some color such as red (255,0,0). By applying the mask to the white color: red is chosen (255 & 255, 255 & 0, 255 & 0) = (255,0,0)
let tileSize = 2 let DrawTile(pos : Morgemil.Math.Vector2i, tileDef : Morgemil.Map.TileDefinition) = let drawArea = Rectangle(pos.X * tileSize, pos.Y * tileSize, tileSize, tileSize) spriteBatch.Draw(spriteTexture, drawArea, ChooseColor tileDef) |
Load a ready made dungeon chunk
let chunk = Morgemil.Map.DungeonGeneration.Generate 216798 |
Draw it to the screen
override this.Draw(gameTime) = this.GraphicsDevice.Clear Color.Black spriteBatch.Begin() chunk.TileCoordinates |> Seq.iter (DrawTile) spriteBatch.End() |
Make sure that the entire map is shown on the screen. By modifying the buffer on the graphics device manager earlier.
let graphics = new GraphicsDeviceManager(this) do graphics.PreferredBackBufferWidth <- chunk.Area.Width * tileSize do graphics.PreferredBackBufferHeight <- chunk.Area.Height * tileSize do graphics.ApplyChanges() |
Here is the result
And here is the full code. Cleaning this up and accepting user input could very well be a good choice for next week’s post.
namespace Morgemil.View open Microsoft.Xna.Framework open Microsoft.Xna.Framework.Graphics type GameView() as this = inherit Game() let chunk = Morgemil.Map.DungeonGeneration.Generate 216798 let tileSize = 2 let graphics = new GraphicsDeviceManager(this) do graphics.PreferredBackBufferWidth <- chunk.Area.Width * tileSize do graphics.PreferredBackBufferHeight <- chunk.Area.Height * tileSize do graphics.ApplyChanges() let mutable spriteBatch = Unchecked.defaultof<SpriteBatch> //null let mutable spriteTexture = Unchecked.defaultof<Texture2D> //null let ChooseColor(tileDef : Morgemil.Map.TileDefinition) = match tileDef.BlocksMovement with | true -> Color.Black | false -> Color.White let DrawTile(pos : Morgemil.Math.Vector2i, tileDef : Morgemil.Map.TileDefinition) = let drawArea = Rectangle(pos.X * tileSize, pos.Y * tileSize, tileSize, tileSize) spriteBatch.Draw(spriteTexture, drawArea, ChooseColor tileDef) override this.Initialize() = base.Initialize() base.Window.Title <- "Morgemil" override this.LoadContent() = spriteBatch <- new SpriteBatch(this.GraphicsDevice) spriteTexture <- new Texture2D(this.GraphicsDevice, 1, 1) //Only need 1 color spriteTexture.SetData([| Color.White |]) //255,255,255 override this.Update(gameTime) = () override this.Draw(gameTime) = this.GraphicsDevice.Clear Color.Black spriteBatch.Begin() chunk.TileCoordinates |> Seq.iter (DrawTile) spriteBatch.End() |