Creating your first sample game with MonoGame
In this post I provide an introduction to the MonoGame framework. I start by looking at the history of MonoGame and the XNA framework and then show how to get started with MonoGame. Finally we take a look at a default sample app. In my next post I will show how I used MonoGame to port a Microsoft XNA game from 2009 to run on .NET 8 in just a few hours.
Background: A brief history of Microsoft XNA and MonoGame
Microsoft’s XNA framework was first announced back in 2004 (and first released in preview in 2006) as a set of tools for building video games that would run on Windows and Xbox 360 (and later, Windows phone). The Microsoft XNA framework was originally based on .NET Framework 2.0 on Windows and .NET Compact Framework on Xbox 360, with this later being updated to support .NET Framework 3.5.
The XNA framework was meant to provide an easy way of writing games that focused on the content, rather than having to think about all the minutia that would change between platforms. It had a big focus on indie games, where gameplay is the key attraction, rather than the focus being the highest performance or the best graphics. XNA didn’t provide a full game engine, instead providing lower-level abstractions, as well as a collection of tools for building content-pipelines and such.
Shortly after the XNA framework was released and was heavily promoted by Microsoft, a project called Mono.XNA was created. Much as Mono was intended as an open-source cross-platform version of .NET Framework, so Mono.XNA was conceived as an open-source cross-platform version of Microsoft XNA, enabling users to build games that would run on Windows, Mac, and Linux, using OpenGL for rendering. At around the same time, Bill Reiss started a project called SilverSprite, with the goal of running XNA games in the browser, using Silverlight 2.0, and later 3.0.
In 2009 José Antonio Leal de Farias, started an open-source project called XNA.Touch, with the goal of porting simple 2D XNA games to mobile. XNA.Touch used code primarily from SilverSprite and some parts from Mono.XNA to create a framework that enabled running XNA games on the iPhone. This culminated in 2010 with multiple games being released to the Apple App Store.
In 2011, XNA.Touch was renamed to MonoGame. MonoGame added support for Android, Mac, Linux, Windows (using OpenGL) in the same year; they added support for DirectX 11, Windows 8, and Windows 8 Phone in 2012; and then in 2013 they added support for the PlayStation 4. Today, MonoGame even supports PlayStation 5 and Nintendo Switch.

Today, MonoGame implements the Microsoft XNA 4.0 API. Just as for XNA, MonoGame provides the building blocks to build your own engine and tools, but it isn’t quite an engine itself. It also provides a bunch of tools for working with content (similar to the tools XNA provided).
Getting started with MonoGame
Getting started with MonoGame is incredibly simple if you’re already a .NET developer. There are basically only two steps:
- Install the .NET 8 SDK (or newer)
- Install the MonoGame templates
I obviously already had the .NET 9 SDK installed, so all that remained was to install the MonoGame templates with:
dotnet new install MonoGame.Templates.CSharp
After installing the templates you have a bunch of templates available:
The following template packages will be installed:
MonoGame.Templates.CSharp
Success: MonoGame.Templates.CSharp::3.8.3 installed the following templates:
Template Name Short Name Language Tags
MonoGame 2D StartKit mg2dstartkit [C#] MonoGame/Games/Mobile/Android/iOS/Desktop/Windows/Linux/macOS
MonoGame Android Application mgandroid [C#] MonoGame/Games/Mobile/Android
MonoGame Blank 2D StartKit mgblank2dstartkit [C#] MonoGame/Games/Mobile/Android/iOS/Desktop/Windows/Linux/macOS
MonoGame Content Pipeline Extension mgpipeline [C#] MonoGame/Games/Extensions
MonoGame Cross-Platform Desktop Application mgdesktopgl [C#] MonoGame/Games/Desktop/Windows/Linux/macOS
MonoGame Game Library mglib [C#] MonoGame/Games/Library
MonoGame iOS Application mgios [C#] MonoGame/Games/Mobile/iOS
MonoGame Shared Library Project mgshared [C#] MonoGame/Games/Library
MonoGame Windows Desktop Application mgwindowsdx [C#] MonoGame/Games/Desktop/Windows/Linux/macOS
MonoGame supports all the IDEs you would expect (Visual Studio, VS Code, and Rider). I was just going to use the OpenGL-based application, so as far as I could tell, I didn’t need to install any additional components. If you’re using one of the other templates, then you may need to install additional components using Visual Studio or the dotnet CLI, as described in the documentation.
With the templates installed, I set about creating my first MonoGame application.
Creating my first MonoGame application
Before creating the MonoGame project, I created a solution to hold the project. Just to try it out, I decided to use the new slnx format seeing as Rider supports it.
As far as I can tell, you can’t create a slnx file directly using the .NET CLI, so I created a new sln file, and converted it instead:
# Create the new sln file
dotnet new sln
# Convert the sln file to a slnx file
dotnet sln migrate
# Delete the original sln file
rm *.sln
Next I created a “MonoGame Cross-Platform Desktop Application” using the mgdesktopgl
template:
Create the project
# Create the template in a “MyGame” subfolder
dotnet new mgdesktopgl –output MyGame
# Add the new project to the template
dotnet sln add ./MyGame/
We now have our sample application. Before testing it out, let’s take a look at some of the files it includes.
Exploring the default MonoGame template
We’ll start by looking at the project template. As you can see below, the project is a .NET 8 app, which adds a couple of embedded resources for the app icon. It references two NuGet packages:
MonoGame.Framework.DesktopGL
—This is the “main” MonoGame NuGet package for the sample that includes the required implementation for creating a cross-platform desktop application based on OpenGL. There are other packages for other MonoGame targets.MonoGame.Content.Builder.Task
—This small package contains MSBuild properties and tasks for running MonoGame’s content pipeline.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RollForward>Major</RollForward>
<PublishReadyToRun>false</PublishReadyToRun>
<TieredCompilation>false</TieredCompilation>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="Icon.ico" />
<None Remove="Icon.bmp" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Icon.ico">
<LogicalName>Icon.ico</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Icon.bmp">
<LogicalName>Icon.bmp</LogicalName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8." />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8." />
</ItemGroup>
<Target Name="RestoreDotnetTools" BeforeTargets="Restore">
<Message Text="Restoring dotnet tools" Importance="High" />
<Exec Command="dotnet tool restore" />
</Target>
</Project>
Another interesting point is the additional MSBuild target RestoreDotnetTools
which runs dotnet tool restore
just before restoring NuGet packages. This restores the various mgcb
dotnet tools that are included as part of the manifest in .config/dotnet-tools.json. These are the MonoGame Content Builder (MGCB) tools which provide graphical and command-line tools for editing and optimising your content for processing:
{
“version”: 1,
“isRoot”: true,
“tools”: {
“dotnet-mgcb”: {
“version”: “3.8.3”,
“commands”: [ “mgcb” ]
},
“dotnet-mgcb-editor”: {
“version”: “3.8.3”,
“commands”: [ “mgcb-editor” ]
},
“dotnet-mgcb-editor-linux”: {
“version”: “3.8.3”,
“commands”: [ “mgcb-editor-linux” ]
},
“dotnet-mgcb-editor-windows”: {
“version”: “3.8.3”,
“commands”: [ “mgcb-editor-windows” ]
},
“dotnet-mgcb-editor-mac”: {
“version”: “3.8.3”,
“commands”: [ “mgcb-editor-mac” ]
}
}
}
The manifest includes 5 different tools:
dotnet-mgcb
—The MonoGame Content Builder (MGCB) command line tool is used for optimizing content for runtime use.dotnet-mgcb-editor
—The MonoGame Framework Content Builder Editor (MGCB-Editor) is a graphical tool used for editing your content projects ready for processing. There are Windows/Linux/Mac specific versions of the tool, but as far as I can tell, you can just run the generic tool.
Finally, we come to the code. The Program.cs file leverages all the modern .NET goodness to be just two lines:
using var game = new MyGame.Game1();
game.Run();
Finally, we can see the Game1
class itself. This very simple example includes the basics—creating a GraphicsDeviceManager
and a SpriteBatch
—but mostly highlights the different stages in the XNA/MonoGame game loop that you should override to create your own game.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace MyGame;
public class Game1 : Game
{
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
<span class="token keyword">public</span> <span class="token function">Game1</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
_graphics <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">GraphicsDeviceManager</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Content<span class="token punctuation">.</span>RootDirectory <span class="token operator">=</span> <span class="token string">"Content"</span><span class="token punctuation">;</span>
IsMouseVisible <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Initialize</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">// TODO: Add your initialization logic here</span>
<span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">Initialize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">LoadContent</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
_spriteBatch <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">SpriteBatch</span><span class="token punctuation">(</span>GraphicsDevice<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// TODO: use this.Content to load your game content here</span>
<span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Update</span><span class="token punctuation">(</span><span class="token class-name">GameTime</span> gameTime<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>GamePad<span class="token punctuation">.</span><span class="token function">GetState</span><span class="token punctuation">(</span>PlayerIndex<span class="token punctuation">.</span>One<span class="token punctuation">)</span><span class="token punctuation">.</span>Buttons<span class="token punctuation">.</span>Back <span class="token operator">==</span> ButtonState<span class="token punctuation">.</span>Pressed <span class="token operator">||</span> Keyboard<span class="token punctuation">.</span><span class="token function">GetState</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">IsKeyDown</span><span class="token punctuation">(</span>Keys<span class="token punctuation">.</span>Escape<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token function">Exit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// TODO: Add your update logic here</span>
<span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">Update</span><span class="token punctuation">(</span>gameTime<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Draw</span><span class="token punctuation">(</span><span class="token class-name">GameTime</span> gameTime<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
GraphicsDevice<span class="token punctuation">.</span><span class="token function">Clear</span><span class="token punctuation">(</span>Color<span class="token punctuation">.</span>CornflowerBlue<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// TODO: Add your drawing code here</span>
<span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">Draw</span><span class="token punctuation">(</span>gameTime<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
}
Aside from some basic setup, the sample game essentially contains just two behaviours:
- Listen for the Escape key on the keyboard, or the Back button on a keypad, and exit the game if they’re pressed.
- Pain the colour Cornflower Blue as the game background.
And that’s essentially all there is to it. You can run the template using dotnet run
, or by pushing F5 in your IDE. The resulting “game” just shows a blue screen until you hit exit:
And that’s all there is to it. In the next post I’ll show how I started from this sample to port a Microsoft XNA game from 2009 to run on .NET 8 in just a few hours.
Summary
In this post I described a brief history of the Microsoft XNA framework and the creation of MonoGame as an open-source implementation of the Microsoft XNA 4.0 API. I then discussed the basic requirements for building a MonoGame Windows application: the .NET 8 SDK and the .NET CLI templates. Finally, we took a tour of the sample app to see the relevant NuGet packages, tools, and code that the sample uses. In the next post I’ll show how I started from this sample to port a Microsoft XNA game to MonoGame in just a few hours.