MonoGame Tutorial: Build Your First 2D Game Step by Step
MonoGame is a free, open-source .NET framework for 2D and 3D games written in C# — the modern successor to Microsoft's XNA. This tutorial walks through building your first MonoGame project from scratch: install the .NET SDK, create a project with dotnet new, understand the Game1 game loop, load a texture, draw a sprite with SpriteBatch, and move it with the keyboard. By the end you have a window with a player sprite you can steer, plus a clear path to collisions, animation, and audio.
MonoGame is a free, open-source .NET framework for making 2D and 3D games in C# — the community-maintained successor to Microsoft's XNA. In this tutorial you will build a real first project from an empty folder to a window with a player sprite you steer with the arrow keys, and along the way learn the parts of MonoGame that every game reuses: the project template, the game loop, texture loading, SpriteBatch drawing, and keyboard input.
You do not need an engine, and you do not need Visual Studio. All you need is the .NET SDK and a text editor. The current stable MonoGame release is 3.8.4.1 (June 2025); version 3.8.5 is available as a preview but is not final yet.
What you will build
A minimal but complete MonoGame game: a 800×600 window containing a sprite that moves when you press the arrow keys. That covers roughly 80% of what a 2D MonoGame game does — load an image, draw it every frame, and read input to change something. Collisions, animation, and sound are then extensions on this same loop.
Step 0 — Install the .NET SDK
MonoGame runs on .NET, so install the .NET 8 SDK (or newer) from dotnet.microsoft.com/download. Verify it works:
dotnet --version
That single command is all the setup MonoGame needs at the system level. The framework itself comes in through NuGet when you create a project — no separate installer required.
Step 1 — Create the project
MonoGame ships project templates as a NuGet package. Install them once:
dotnet new install MonoGame.Templates.CSharp
Then create a DesktopGL project — the cross-platform template that runs on Windows, macOS, and Linux:
dotnet new mgdesktopgl -o MyFirstGame
cd MyFirstGame
mgdesktopgl is the short name for the DesktopGL template. Other templates exist for specific targets: mgwindows (Windows DirectX), mgandroid, and mgios. For a first game, DesktopGL is the right choice because it runs everywhere you develop.
Step 2 — Understand Game1.cs
Open Game1.cs. The template generates a class built around four methods, and this is the game loop that every MonoGame game is built on:
public class Game1 : Game
{
private 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) { base.Update(gameTime); }
protected override void Draw(GameTime gameTime) { }
}
The four methods run on a strict cycle, inherited from XNA:
| Method | When it runs | What you do here |
|---|---|---|
Initialize | Once, at startup | Set up non-graphics state, query services |
LoadContent | Once, at startup | Load textures, fonts, sounds |
Update | Every frame | Read input, move objects, run game logic |
Draw | Every frame | Render everything to the screen |
The cycle is Update → Draw → Update → Draw, dozens of times per second. Keep logic in Update and drawing in Draw, and you have the structure of a game.
Step 3 — Load a texture
Add a PNG image to your project folder (for example, player.png, any small square image will do). MonoGame gives you two ways to load it. The fastest for a first game is to skip the content pipeline and load the file directly:
private Texture2D _playerTexture;
private Vector2 _playerPosition;
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
_playerTexture = Texture2D.FromFile(GraphicsDevice, "player.png");
_playerPosition = new Vector2(400, 300);
}
Texture2D.FromFile reads the PNG at runtime with no build step. The alternative — the MonoGame Content Builder (MGCB) — compiles assets into optimized .xnb files you load with Content.Load<Texture2D>("player"). The pipeline is faster at runtime and is required for shaders and effects (.fx), but for a first project loading a PNG directly keeps the focus on the game loop. You can move to the pipeline later.
Step 4 — Draw the sprite
SpriteBatch is MonoGame's main 2D drawing tool. Every frame, open it, draw, and close it:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
_spriteBatch.Begin();
_spriteBatch.Draw(_playerTexture, _playerPosition, Color.White);
_spriteBatch.End();
base.Draw(gameTime);
}
Clear wipes the screen each frame (the classic XNA cornflower-blue background). Between Begin and End, SpriteBatch batches draw calls and sends them to the GPU efficiently — so put all your Draw calls for a frame inside one Begin/End pair.
Step 5 — Move with the keyboard
Now make the sprite respond to input. In Update, read the keyboard state and change the position:
protected override void Update(GameTime gameTime)
{
var keyboard = Keyboard.GetState();
float speed = 200f * (float)gameTime.ElapsedGameTime.TotalSeconds;
if (keyboard.IsKeyDown(Keys.Left)) _playerPosition.X -= speed;
if (keyboard.IsKeyDown(Keys.Right)) _playerPosition.X += speed;
if (keyboard.IsKeyDown(Keys.Up)) _playerPosition.Y -= speed;
if (keyboard.IsKeyDown(Keys.Down)) _playerPosition.Y += speed;
base.Update(gameTime);
}
Two things matter here. First, Keyboard.GetState() returns the current state of every key, and IsKeyDown checks one. Second, movement is multiplied by ElapsedGameTime so the speed is per second, not per frame — your player moves at the same rate on a 60 Hz laptop and a 144 Hz monitor. Get this habit right from the first tutorial and you avoid the "my game runs too fast on a new PC" class of bugs forever.
Step 6 — Run it
dotnet run
A 800×600 window opens, the cornflower-blue background clears each frame, and your sprite moves with the arrow keys. You now have a working MonoGame game. The full Game1.cs is just the four methods above, fitted together.
Where to go next
From here, every 2D feature is an addition to the same loop:
- Collisions — check the bounding rectangles of two sprites with
Rectangle.IntersectsinsideUpdate. - Animation — store an array of source rectangles on a sprite sheet and advance the index on a timer.
- Audio — load a
SoundEffectthrough the content pipeline and call.Play(). - Text — load a
SpriteFontand draw strings with_spriteBatch.DrawString. - Shaders — write a
.fxeffect, compile it through MGCB, and apply it inSpriteBatch.
When you reach the point of needing a scene editor, tile maps, and visual logic rather than hand-written code, that is where a tool built on MonoGame becomes useful. See the 8 MonoGame tools pro developers use, the stories and lessons of MonoGame indie developers, and how to ship a MonoGame game solo.
Common mistakes
- Mixing logic into
Draw. Keep input and movement inUpdate.Drawshould only render the current state. - Forgetting to multiply movement by elapsed time. Movement becomes frame-rate-dependent and runs at different speeds on different machines.
- Opening multiple
SpriteBatchpairs per frame. OneBegin/Endper batch is cheaper than many. - Calling
Content.Loadevery frame. Load once inLoadContentand store the reference; loading each frame thrashes memory. - Using raw pixel coordinates as physics units. If you add a physics engine later, it expects meters, not pixels. See the 2D physics engine guide for why scale matters.
Where Egmatic fits
MonoGame gives you C#, .NET, full source access, no royalties, and the same reach as the stack behind Stardew Valley and Celeste — but you assemble every layer yourself. Egmatic is a 2D game editor and engine built on the MonoGame runtime, so the scene editor, content pipeline, and node-based logic are integrated rather than wired together by hand. You keep MonoGame's cross-platform reach and drop the integration work. If you want the power of the MonoGame stack without spending weeks stitching tools together, that is what Egmatic is for.
Conclusion
A first MonoGame game is four methods: Initialize, LoadContent, Update, and Draw. Install the .NET SDK, create a project with dotnet new mgdesktopgl, load a texture, draw it with SpriteBatch, and move it with Keyboard.GetState. That is the whole loop, and collisions, animation, and audio are all additions to it. Run it with dotnet run, and you have a window with a sprite you control — the honest starting point for every MonoGame game that comes after.
Related Posts
10 Best Prototyping Tools for Rapid Game Development (2026)
The right prototyping tool cuts weeks off your game development cycle. Here are 10 tools ranked by speed, cost, and suitability for 2D game prototyping — from no-code engines to professional frameworks.
10 Best Sprite Animation Software Tools for 2026
The right sprite animation tool depends on your art style, your budget, and your pipeline. This guide compares ten tools — Aseprite, Piskel, LibreSprite, Spine, DragonBones, Krita, GraphicsGale, Pro Motion NG, Blender, and Adobe Animate — with verified 2026 pricing, feature breakdowns, and clear recommendations based on project type.
12 Best Prototyping Software for Game Developers: 2026 Review
We tested 12 game prototyping tools — GDevelop, Construct 3, Egmatic, GameMaker, Godot, Unity, Buildbox, RPG Maker, Stencyl, Cocos Creator, Flowlab, and Scratch — on real projects. This review covers pricing, learning curve, export options, and which tool actually produces a prototype worth building on.