(This is a re-post from my original blog, originally posted on the 24th of February 2013 - content was correct at the time of writing and is posted here for archival purposes)
I need to update this post with a better code block system, unfortunately the style built into Ghost doesn't work that well. Apologies in advance and hopefully this will be fixed up soon.
MonoGame is the latest and greatest if you’re looking to bring your XNA skills over to extra platforms, including the Windows 8 Store. The huge benefit is that the MonoGame namespaces are the same as the XNA ones, allowing for easy porting of existing XNA projects.
The main issue at the moment with creating projects from scratch is that there is no replacement (yet) for the Content Pipeline, and until it is added you have to install Visual Studio 2010 to get XNA Game Studio 4.0 working, or use the WP8 SDK and copy files or use dummy WP8 class libraries.
With a bit of MSBuild magic (disclaimer: not really magic) we can integrate the content build into the MonoGame project build, gain incremental builds and have the files automatically copied and included in any appx packages we may create.
- Install MonoGame 3.0 (MonoGame Downloads)
- Install the Windows Phone 8 SDK to get Content projects in Visual Studio 2012 (WP8 SDK Download)
- Create a MonoGame Project
- Create an XNA Game Studio 4.0 Content Project
- Add some content
- Write your game
Now you’re ready to continue with this guide.
MSBuild uses Targets to define the actions that are taken during a build. These targets can be selected from the command line to do things like clean the project or run special builds. This is also what is used to run the Before and After build events. We will make use of the BeforeBuild event to trigger a content build and set things up so the compiled content is included in the project.
A task is what is executed inside the build target. This can range from executing a command line process to a separate MSBuild configuration. The tasks inside a target are executed sequentially in the order specified in XML.
Items and ItemGroups
Items define the files and parts of a build. These are often the files you see in the Visual Studio Solution Explorer, however they can also include references, resources and even output from build tasks. We will make use of items to easily add the built content to our MonoGame build.
Properties and PropertyGroups
Properties define variables that are used by MSBuild to configure and run the build. An easy example of this is the Configuration and Platform properties that control optimisation and other properties during the build. We will use properties to specify some variables that can be used in our build target, which will allow changing the name of the content project to be easier.
Making the Changes
First open the csproj of the main game project. To do this inside Visual Studio, you need to load the solution and then unload the project you want to edit. You can unload the project by right clicking the project in the solution explorer and selecting Unload Project. Then right click on the unloaded project and choose Edit. You should now see an XML file in the editing area.
We want to add a BeforeBuild target to the file, this usually sits at the end of the file. You may have already specified part of the BeforeBuild target if you have created a build event in Visual Studio. If so, just add in the child XML of the <Target> tag. If not, just copy the following into the end of your project file, before the closing </Project> tag.
<MSBuild Projects="$(SolutionDir)$(ContentProject)\$(ContentProject).contentproj" Properties="XNAContentPipelineTargetProfile=Reach;XNAContentPipelineTargetPlatform=Windows" /><ItemGroup>
<XNAContent Include="$(SolutionDir)\$(ContentProject)\bin\$(Platform)\$(Configuration)\**\*.xnb" />
</ItemGroup> <Copy SourceFiles="@(XNAContent)" DestinationFiles="@(XNAContent->'$(ProjectDir)\%(RecursiveDir)\%(Filename)%(Extension)')" /> <ItemGroup> <Content Include="$(ProjectDir)\$(ContentDirectory)\**\*.xnb" /> </ItemGroup> </Target>
This code assumes that you have an XNA Content Project on the same level as your game project. If not, change the path in the Projects property of the MSBuild tag.
Inside this code you’ll notice that we have some parts with a $, @ and % in front. The $ in front means a reference to a property. This is what we use to build a path to the content project. I will outline how to define the ContentProject property soon.
The @ symbol refers to items defined in the project, both inside and outside of the task.
The % symbol defines a sub-property, such as the Filename of an item. We can use this to transform the path of an item into another path where required.
Here we are executing MSBuild for the content project, and specifying some properties that are normally specified by the XNA Game. These properties are:
These are XNA specific values, and because we’re building a Windows Store project, we use Windows and Reach. HiDef can be used if you aren’t sharing XNA code with Windows Phone 7 or want to upgrade the capabilities of your game.
To define the properties, add the following tag block somewhere inside the <Project>. The best place is just above the BeforeBuild target, so you know where to find it if you need to change it.
These properties allow you to specify the name of the .contentproj file, as well as the directory that the file is stored in. Remember that we assume the directory structure to be as follows: (make changes if yours differs)
Now you can reload the project by right clicking the solution and selecting Reload. Be careful, your start-up project may have changed, so fix that before building.
Now you should be able to hit F5 and watch as your content is built and included in your Windows Store package to be deployed and used by the MonoGame content loader.
If you have any questions please feel free to ask them in the comments. Feedback and suggestions are also welcome.
I’ll be looking at the possibility of creating a template that adds a WP8 content project with this code to the normal MonoGame project. Hopefully that works and I can get that published soon. I’ll update this post (and post a new one) if that happens.