Core Loop & States
Anatomy of a MonoGame Project
A new MonoGame DesktopGL project looks small, but every generated file has a job. This tutorial walks through the entry point, the Game1 class, the project file, content building, generated folders, and how assets flow from your source files into the running game.
Download the runnable sample project
Use the verified ZIP bundle for this article to review the extracted example files, run the sample host, and repackage the sources without bin or obj folders.
The generated project tree
When you create a MonoGame DesktopGL project from the modern .NET templates, the starting structure is intentionally simple. The names may vary slightly depending on your project name, but the responsibilities are the same.
MyGame/
MyGame.csproj
Program.cs
Game1.cs
Icon.ico
app.manifest
Content/
Content.mgcb
bin/
DesktopGL/
Content/
*.xnb
obj/
DesktopGL/
.config/
dotnet-tools.json
bin/
Debug/
net8.0/
obj/
Debug/
net8.0/
The important split is between source files you edit and generated files the tools recreate. You edit Program.cs, Game1.cs, MyGame.csproj, Content/Content.mgcb, and your art, audio, font, or effect files. The bin and obj folders are build outputs.
💡 Beginner rule: if the file describes your game or an asset you created, keep it. If it is under bin or obj, it is usually generated and can be rebuilt.
⚠️ Caution: Do not delete Content/Content.mgcb. It is not a generated output; it is the source content project that tells MonoGame which assets to process.
Program.cs: the entry point
Program.cs is where the application starts. In the template it creates one instance of your game class, runs it, and then disposes it safely when the game exits.
using var game = new Game1();
game.Run();
using var means the Game1 object is disposed automatically at the end of the scope. game.Run() hands control to MonoGame, opens the window, starts the game loop, and keeps running until Exit() is called or the window closes.
⚠️ Caution: Avoid putting game logic in Program.cs. Keep it as the launcher. Your loading, input, update, and drawing code belong in Game1.cs or classes called by Game1.
Game1.cs: your Game subclass
Game1.cs contains a class that inherits from Microsoft.Xna.Framework.Game. That base class owns the window, timing, lifecycle, and main loop. You override methods to configure your game, load content, update state, and draw frames.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
public class Game1 : Game
{
private readonly GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected override void Update(GameTime gameTime)
{
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
}
}
GraphicsDeviceManagerconfigures graphics options such as preferred back-buffer size, fullscreen mode, and vertical sync.Content.RootDirectory = "Content"tells the content manager where compiled assets are rooted at runtime.SpriteBatchis commonly created once inLoadContentand reused when drawing 2D textures and text.Updatereads input and changes game state.Drawclears the screen and renders the current state.
💡 Rename Game1 later if you like, but rename it consistently in the class declaration, constructor, filename, and Program.cs.
The .csproj file
The .csproj file is the .NET project file. It says what kind of application you are building, which .NET target framework to use, and which NuGet packages provide MonoGame and the content builder.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RollForward>Major</RollForward>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.2.1105" />
</ItemGroup>
</Project>
TargetFramework chooses the .NET runtime your project builds against. MonoGame.Framework.DesktopGL supplies the cross-platform DesktopGL framework. MonoGame.Content.Builder.Task integrates content building into dotnet build, so assets listed in Content.mgcb are compiled before the game runs.
⚠️ Caution: Keep MonoGame package versions aligned. Mixing framework and content-builder versions can cause confusing build errors, especially after updating templates or restoring an old project.
Content.mgcb and the content pipeline
Content/Content.mgcb is the MonoGame Content Builder project. Open it with the MGCB Editor to add textures, sprite fonts, effects, sounds, songs, and other supported assets. The editor stores importer, processor, and build settings in the .mgcb file.
#----------------------------- Global Properties ----------------------------#
/outputDir:bin/$(Platform)
/intermediateDir:obj/$(Platform)
/platform:DesktopGL
/profile:Reach
#-------------------------------- References --------------------------------#
#---------------------------------- Content ---------------------------------#
#begin player.png
/importer:TextureImporter
/processor:TextureProcessor
/build:player.png
#begin Fonts/DefaultFont.spritefont
/importer:FontDescriptionImporter
/processor:FontDescriptionProcessor
/build:Fonts/DefaultFont.spritefont
The content pipeline converts editable source files into runtime-friendly .xnb files. For example, player.png might build to Content/bin/DesktopGL/Content/player.xnb during content building and then be copied beside your compiled game.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
public class Game1 : Game
{
private SpriteBatch _spriteBatch;
private Texture2D _playerTexture;
private SpriteFont _defaultFont;
public Game1()
{
Content.RootDirectory = "Content";
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
_playerTexture = Content.Load<Texture2D>("player");
_defaultFont = Content.Load<SpriteFont>("Fonts/DefaultFont");
}
}
Content.RootDirectory = "Content" sets the runtime root. Content.Load<Texture2D>("player") looks for a compiled asset named Content/player.xnb. Content.Load<SpriteFont>("Fonts/DefaultFont") maps to Content/Fonts/DefaultFont.xnb. You do not include the .xnb extension in Content.Load.
⚠️ Caution: Loading uses the asset name from the content project, not necessarily the original file extension. Use Content.Load<Texture2D>("player"), not Content.Load<Texture2D>("player.png").
💡 If an asset fails to load, check three things first: it is added to Content.mgcb, it builds successfully to .xnb, and the string passed to Content.Load matches the built asset path without an extension.
Generated files and folders
MonoGame and .NET create several folders while building. These folders are useful for the tools, but they are not the source of truth for your game.
bin/contains compiled application output such as your executable, DLLs, copied assets, and runtime configuration.obj/contains intermediate files used by the compiler and build system.Content/bin/contains compiled content output from MGCB, usually including.xnbfiles.Content/obj/contains intermediate content-build files.
It is normally safe to close the game and delete bin and obj folders if a build gets into a strange state. The next dotnet build recreates them.
app.manifest describes Windows application metadata used by the generated executable. Icon.ico is the application icon. The .config/dotnet-tools.json file records local .NET tools used by the project or template, such as MGCB-related tooling, so another developer can restore them with dotnet tool restore.
⚠️ Caution: Do not edit files inside obj to fix source problems. Those files are regenerated. Fix the original .cs, .csproj, or .mgcb file instead.
DesktopGL vs WindowsDX
The DesktopGL template uses MonoGame.Framework.DesktopGL and OpenGL through a desktop backend. It is the usual choice when you want one project that can target Windows, Linux, and macOS with the same MonoGame API.
The WindowsDX template uses the Windows DirectX backend. It is Windows-focused and can be useful when you specifically want DirectX behaviour or compatibility with Windows-only graphics expectations. Your Game1 code is usually very similar, but the framework package, platform setting, native dependencies, and content platform differ.
💡 For beginners, start with DesktopGL unless you have a Windows-only reason to choose WindowsDX. It keeps the project portable while you learn the MonoGame lifecycle and content pipeline.
Build, content-build, run flow
A normal run is a short pipeline. The .NET SDK restores packages, compiles C# code, MonoGame builds the content project, and then the game starts. If content is already up to date, the content-build step may finish quickly.
dotnet tool restore
dotnet restore
dotnet build
dotnet run
# If generated output looks stale, clean and rebuild:
dotnet clean
dotnet build
- Restore downloads NuGet packages and local tools described by the project.
- Compile checks your C# files and emits the game assembly.
- Content-build reads
Content/Content.mgcband converts assets to.xnb. - Copy output places compiled content under the runtime
Contentfolder beside the game output. - Run executes
Program.cs, which createsGame1and callsRun().
Next steps
🎓 Test Your Knowledge
Check your understanding of the key concepts from this tutorial.
What class does your MonoGame game's main class inherit from?
✔ Correct!
✘ Not quite.
All MonoGame games extend the Game base class. SpriteBatch is a drawing helper, and GraphicsDevice represents the GPU.
What is the purpose of the ContentManager?
✔ Correct!
✘ Not quite.
ContentManager.Load<T> loads compiled .xnb assets and caches them for reuse.
Which folder contains compiled content assets ready for the Content Pipeline?
✔ Correct!
✘ Not quite.
Content/ holds the .mgcb project and compiles assets into the bin subfolder at build time.
When is GraphicsDeviceManager created?
✔ Correct!
✘ Not quite.
GraphicsDeviceManager must be created in the constructor so the window and graphics device are ready before Initialize runs.