Managing Content

Managing Content

Introduction

In this tutorial, we're going to cover content and content management in your MonoGame project.

The Content Problem

Games have a substantially higher amount of content than most types of software.
By content, I'm referring to all of the various creative assets that the game needs to run: 3D models, textures, UI images, sprites, sound effects, music, level data, and anything else that feeds into the game.

The catch is that the format of these content files is not ideally suited to immediate use in a game. The formats are typically optimized for editing or perhaps for data transfer, but not for immediate game usage.

That means they usually need to be transformed from their normal format into a game-ready format. You could do that in one of three places:

1. By the original program (called a "Digital Content Creation tool" or DCC). The format that is ideal for your game is not going to be the same as what is needed for other games, so this would typically demand a custom-made plugin for each DCC software.
2. By the game when it is loading its resources.
3. Some time in the middle, such as compile time.

The first one is a little tricky. It pushes the conversion to the content creators, which are usually artists of some sort. But it also means you're going to have to make plugins for whatever program the artists are using, and maintain them as the artists change or upgrade their tools.

The second option is also tricky for a number of reasons. First, it demands running it on the player's device, which might even include a mobile device with limited capabilities. Having the conversion happen at runtime makes it slower, and demands a larger file size as well.

The third option is the one typically used in game development. It happens outside of the original DCC tools, lessening the burden on artists. The conversion happens at compile time, taking the load off the player's devices as well. This is the option that MonoGame uses as well.

The conversion process from standard content format to game-ready format is called the content pipeline, because it is made up of several stages. We won't get into the details of these stages in this tutorial, but later tutorials will cover it.

Managing Content in MonoGame

For the rest of this tutorial, we will walk through how to add content files to your MonoGame project and load them into your game. This skill is an important one that you will perform often, so it is good to get comfortable with the process early.

The MGCB File

Any content file that you want to send through the content pipeline needs to be added to a file in your MonoGame project called Content.mgcb, which lives in a folder called Content. The extension MGCB stands for MonoGame Content Builder.

You can open this file up in a text editor and modify it that way, but there is a special tool called the MGCB Editor designed to make it easy to edit. I strongly recommend you use the tool instead of trying to edit the file by hand.

Opening the MGCB File with the Editor

The easiest way to open your project's MGCB file in the editor is to find it in the Solution Explorer and double-click on it.

MGCBInSolutionExplorer.png

This will open your content file in the MGCB Editor, ready to modify.

TheMGCBEditor.png

If that does not seem to be working, it may be that you need to configure Visual Studio to associate .mgcb files with the MGCB Editor. You can do that by right-clicking on your MGCB file in the Solution Explorer and choosing Open With…, and then finding MGCB Editor in the list, clicking Set as Default, and then pressing OK. After doing this, the next time you open the file, you should be able to simply double-click on it.

Adding Content Files

There are two main ways to add content files to your MGCB file. The first is to reference an existing file made in another program. For example, you can add a .png image, a .mp3 audio clip, or an .fbx 3D model. The second is to make a new file. This second option is mostly only used for content that isn't typically made by an artist in another program, such as a sprite font.

To add an existing content file, find the box with a green plus in the toolbar and click it:

AddExisting.png

This will allow you to browse your computer to find the file you want to add.

It will ask you to choose whether you want to copy the file to your project's content directory or add a link to the file.

The answer to this question is usually "Copy the file to the directory." If you are working on a project with others or using version control of any sort, you will want to have all of your content files together. That ensures the whole project is self-contained and will work even if you move between computers or if a teammate tries to use it. The option to link can work fine as well, but requires some extra strategizing to ensure the content files will always be where the link thinks it is at.

To add one of the handful of content files that aren't made in another editor, you instead push the icon with a box with a yellow star in the toolbar:

AddNew.png

Supported File Types and Adding More

The MonoGame content pipeline supports a wide variety of formats. Below is a list of some of the supported file types:

Content Type File Types
3D Models .x, .fbx, .obj
Textures/Images .bmp, .dds, .dib, .hdr, .jpg, .pfm, .png, .ppm, .tga
Audio .xap (an XACT audio project), .wma, .mp3, .wav
Fonts .spritefont
Effects .fx

I'd like the above table to be comprehensive, at least as far as what's available out of the box. Please let me know if you're aware of another file type that it supports natively that isn't listed here.

These formats are usually standard transfer formats rather than specific editor formats. For example, it works with .png and .jpg but not Photoshop's .psd file, and with .obj and .fbx, but not Blender's .blend file. But these content creation tools usually support an option to export in these transfer/interchange formats.

So what happens if you need a format that isn't listed here? The content pipeline is extensible. If a format that you need isn't supported, you have the option to make a content pipeline extension to add support for it. Making content pipeline extensions is not hard but is beyond what we can cover in this tutorial. We'll cover it later.

The image below shows what the editor looks like after adding several image files:

AddedContent.png

Modifying Content File Parameters

We won't get into too many details here, but I want to point out that you can pick a file in the editor and change a whole pile of properties about how the MonoGame content pipeline should handle the file. These settings can all be found in the Properties section in the bottom left, once you have selected a file. It is worth taking a look at them now for any file you may have added. They differ depending on the file type, meaning images will have a different set of options than music, for example.

The defaults are often the right option in most situations, but sometimes, you need to massage these parameters to get it to process your content file just right.

Organizing Content with Folders

The last thing I want to mention about the MGCB Editor is that you can create folders to organize your content files. Sometimes, people organize by level. Sometimes, they organize by file type. Use any strategy you want that you feel helps keep things organized. MonoGame doesn't care how you do it.

Adding a new folder is as simple as clicking the icon with a folder and green plus.

Unfortunately, the MGCB Editor does not currently allow you to drag and drop files in the editor. It's an annoying limitation, and perhaps, someday, that feature can be added.

Building Content

When you build a MonoGame project in Visual Studio, it will push all of your files through the content pipeline to give you game-ready assets. However, after I've added a new content file, I like to force it to build immediately to ensure it is working as intended.

That can be done easily by pushing Build > Build from the menu. When you do this, you will see it process all of your files and report if it was successful and, if not, why it failed. The MGCB Editor does a better job at showing you the errors than Visual Studio does, so it is good to see if it is working before going back to Visual Studio.

Loading Content in a Game

The content pipeline has the responsibility of turning a content file into a game-ready asset. When this process finishes, you're left with a game asset stored in a file that you can ship as a part of your game. But the journey isn't done there.

We still need to load the game-ready asset into the game itself. The details of how to use these assets will be covered in more detail in future tutorials, but they all follow a common pattern: you use a ContentManager instance to

In the coming tutorials, we're going to load a lot of content in our games. So a simple example now will help illuminate the pathway.

Given the screenshot from earlier, let's suppose I want to load an art asset that was originally called BlueStar.png.

The simplest way to load this would be as a Texture2D instance, which can be done in the LoadContent method or potentially anywhere afterward. For example:

Texture2D blueStar = Content.Load<Texture2D>("BlueStar");

The variable name does not need to match the name of the content file, and the extension is not necessary.

This uses the generic Load method on a ContentManager instance. The Game base class that Game1 (or whatever you renamed it to) is derived from has a Content property that is such an instance. You're allowed to have other ContentManager instances, as well as pass it around to other classes if you want, but the simplest approach that we'll use in the short term is to just use the game's Content property.

The generic Load method returns a value whose type is the generic type involved. So this particular call will return a Texture2D. A Texture2D is a 2D image in MonoGame Land. If we were expecting it to load a 3D model or a song, we'd use a different type (Model or Song respectively).

Note that the extension of the original file is not included in the name here. This is the name of the asset, not the name of the file, and the original extension is now irrelevant after pushing the content through the pipeline.

If you put your content in a folder, then you must include the folder structure of your content file in the name: "Sprites/Coins/BlueStar", for example.

Lastly, the code above stores the loaded asset in a local variable, presumably in the LoadContent method. In practice, you usually want to load the asset once and then refer back to it when drawing or updating, so most content loaded via Content.Load will be stored in a field at the top of the the main game class or tracked as a part of another object.

We're not going to do anything with our loaded image in this tutorial. We'll save that for the upcoming ones. Right now, it is enough to simply have a grasp on how to push content files through the pipeline and load them into our game when it is running, which we have accomplished now.

Unloading Content in your Game

It is also possible to unload content that was previously loaded by using code like this:

Content.Unload();

This will unload (almost) all of the previously loaded content by the content manager. That means if you want to use something again, you'll have to reload it. But this gives us options for loading and unloading the content for different levels as the player advances.

In small games, you don't have to worry about unloading content. You can just load it all at the beginning and keep it all in memory for the whole time the game runs. For large programs with different content on different levels, you may need to be more careful about what content is loaded at different points in time.

If you want, you can also create additional ContentManager instances to divide up the content. That makes it easier to determine what gets unloaded.

What's Next?

We've discussed how you can load content or art assets in your MonoGame project. This will make it easy to start working on your game, which we're now ready to do!


Troubleshooting.png Having problems with this tutorial? Try the troubleshooting page!