When I wrote this (a little bit each day while working on converting the old XNA projects) I was very aware about the disappointment of my blog readers about the fact that I did not blog much in the last couple of months, especially on XNA. I not only got a lot of emails about that, but also quite a lot of questions, especially since XNA 2.0 was released. I made yet another promise to myself to change that and finally blog more, maybe not only when something very interesting pops up, but instead about the everyday issues I run into.
Some Notes about XNA 2.0: More solid, lots of little new features, networking, while it may not be a very complete solution, at least it is now possible on the Xbox 360 and overall I have the feeling even more people are interested in XNA than a year ago. Plus the guys at the XNA Team doing a great job and are constantly improving the XNA Creators Club website for us game programmers and artists :)
Several people had problems using the old XNA 1.0 code of my games and make them work with XNA 2.0, so here is a little help in case you want to convert XNA 1.0 projects to XNA 2.0. You will also notice this if you go to any XNA community site as most samples will still be in XNA 1.0 and not work out of the box in XNA 2.0, and many of those will probably never be changed since they are not longer actively being developed.
For most games almost all of the code can stay unchanged, you just have to poke at a few things that have changed in the framework or were improved. More information about converting projects can be found here (read this first, this article is based on the stuff there). You can also use the Cross-Platform Game Project Converter from XNA 2.0 to add a Xbox 360 project to your existing Windows XNA project without having to create a separate project (it is helpful, but I used pretty much the same trick for all of my XNA 1.0 games anyway).
Let's go through the steps:
- Either use the XNA project conversion utility (can be found on the XNA Creators Club website) or just create a new XNA 2.0 project in VS 2005.
- If you created a new project, drag all source code files into the project and seperate the content files out and put them all in the existing Content directory (only there the content pipeline is activated). If you just converted a project and the content files did not move, move them yourself to the content directory. Gladly all my projects with more than 5 content files had a special content directory anyway, so no need to change anything content-wise for them. If you don't want some of the files to be compiled to .xnb files, you have to change the build action from "compile" to "content" (and then use the "copy to output directory" switch) or to "none" if you want them to be ignored like for .wav files, which are automatically processed by the .xct (XACT) file for you.
- Find the line content = new ContentManager(Services); and replace it with Content.RootDirectory = "Content";. If you do that, get rid of the content manager in your game class since you can now use the build-in Content property to access the underlying Game content manager. In case you don't want to do that or if you need an extra variable, replace the above line with content = new ContentManager(Services, "Content");. Both ways will make sure all the content is now loaded from the content directory instead from the main directory of the application. In more complex XNA games you can also change the BaseGameDirectory to the content directory, but then you would also have to move all other resource files to this directory (config files, save games, levels, etc.). It is usually a good idea to separate the compiled (.xnb) content from the content the user can change (config, levels, etc.), so I suggest just redirecting the content directory of the content manager.
- Replace the LoadGraphicsContent(bool) method with LoadContent, remove all the if (loadAllContent) commands (was never false anyway, just let the content of the if loop stay) and also remove the call to base.LoadGraphicsContent(bool) (does not do anything like all the Load or Unload methods in the XNA Game class, they are just empty virtual methods). You can also ignore this and the next step since it will only generate depreciated warnings, but I suggest cleaning up your source code whenever an opportunity like this presents itself. I also added some missing region blocks to the code and some comments here and there were they were missing.
- Finally delete the UnloadGraphicsContent method unless it did anything beside base.Unload and base.UnloadGraphicsContent. In my XNA games the UnloadGraphicsContent usually looked like this and can be safely removed now (at least if nothing else is in there):
/// <summary>
/// Unload graphic content if the device gets lost.
/// </summary>
/// <param name="unloadAllContent">Unload everything?</param>
protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent == true)
content.Unload();
base.UnloadGraphicsContent(unloadAllContent);
} // UnloadGraphicsContent(loadAllContent)
- In case you load sound and music via the AudioEngine, you have to change the directory to the content directory too, which will not be done automatically for you since you load the .xct file directly in the AudioEngine constructor. Basically just exchange the following code:
audioEngine = new AudioEngine("YourSound.xgs");
waveBank = new WaveBank(audioEngine, "Wave Bank.xwb");
soundBank = new SoundBank(audioEngine, "Sound Bank.xsb");
with:
audioEngine = new AudioEngine("Content\\YourSound.xgs");
waveBank = new WaveBank(audioEngine, "Content\\Wave Bank.xwb");
soundBank = new SoundBank(audioEngine, "Content\\Sound Bank.xsb");
- In case you have used the StorageDevice and specifically the ShowStorageDeviceGuide helper method, it is gone now in XNA 2.0. I had it in some helper classes, but never actually used it. In case you want to show a save game dialog (or some network game select dialog for example), please follow the XNA 2.0 help instructions to do this asynchronously now.
- In case you use any ResourceUsage enum, replace it with TextureUsage instead or remove it if the issue is not texture related. You can also safely remove any ResourceManagementMode.Automatic parameters, which are not longer supported. Everything is now automatic anyway. Just if you have been using ResourceUsage.RenderTarget you will need to change the Texture2D class to a ResolveTexture2D class in order to archive the same behaviour as before. Some calls to the device (e.g. ResolveBackBuffer) have also changed and require a ResolveTexture2D now. You may also want to check if you have any manual texture management or disposing, which you can remove or simplify.
- For simpler games (2D) games you should be done now. More complex games using render targets and other features that have changed in XNA 2.0 will require some more changes, but after you have done them once (or know where to change what) this is also a quick process.
The following only applies to the RocketCommanderXna, XnaShooter and XnaRacingGame engines, but you might find similarities with other XNA games and the converting process:
- First of all make sure the old XNA 1.1 code gets compileable by going though the changes mentioned above (e.g. replacing ResourceUsage with TextureUsage or BufferUsage) and removing everything that does not exist anymore (like ResourceManagementMode.Automatic). If a method is non-existent in XNA 2.0 like ResolveRenderTarget, comment it out and remember where it happened.
- You might go through other issues, but you have to come back to the RenderTarget issue. This took the most time in the converting process for me (probably half of all my issues come by something related to changes with RenderTargets in XNA 2.0). For that reason always make sure that rendering to textures still works while you make changing. I always used the TestCreateRenderToTexture unit test inside the RenderToTexture class to figure things out.
- Additionally to making some changes in the BaseGame class (loading content via LoadContent, using the base.Content instead of creating a new content manager, etc.) I also removed all the RenderTarget helper methods and fields from the BaseGame class (SetRenderTarget, ResetRenderTarget, etc.) and moved them into the RenderToTexture class. While this makes the code more clean and restructured by making a few more fields private, if you do not call the new InitializeDepthBufferFormatAndMultisampling of the RenderToTexture class the calls to SetRenderTarget and ResetRenderTarget will not work correctly and will not restore the default depth buffer (which has to be remembered first). If you get the following exception it means the DepthBuffer Device.DepthStencilBuffer was set to null, but is obviously still used. In order to fix that make sure the remDepthBuffer variable is set to a correct value in the InitializeDepthBufferFormatAndMultisampling method!
An error has occurred during the Clear operation while trying to clear the depth or stencil buffer, no DepthStencilBuffer surface exists.
System.InvalidOperationException: An error has occurred during the Clear operation while trying to clear the depth or stencil buffer, no DepthStencilBuffer surface exists.
at Microsoft.Xna.Framework.Graphics.GraphicsDevice.Clear(ClearOptions options, Color color, Single depth, Int32 stencil, Rectangle[] regions)
at Microsoft.Xna.Framework.Graphics.GraphicsDevice.Clear(Color color)
- 4. Even if you have now done everything, the app may still crash when you are trying to clear a render target (which usually happens at the start of each pre or post screen shader). The reason for the following error is the multi sampling format, which might be set to the background buffer, but not to the render targets:
The active render target and depth stencil surface must have the same pixel size and multisampling type.
System.InvalidOperationException: The active render target and depth stencil surface must have the same pixel size and multisampling type.
at Microsoft.Xna.Framework.Graphics.GraphicsDevice.VerifyDepthRenderTargetCompat()
at Microsoft.Xna.Framework.Graphics.GraphicsDevice.Clear(ClearOptions options, Color color, Single depth, Int32 stencil, Rectangle[] regions)
In order to get rid of this error without changing the RenderToTexture class a lot, you can just comment out the line where multi sampling is activated in BaseGame:
//this.graphics.PreferMultiSampling = true;
There are probably even more things that I forgot while converting the projects (converted 8 games and about 15 projects in total now), but the above list should be helpful. Especially for me because I always forget some of those little things and having this checklist is very helpful.
Tomorrow I will probably test all the XNA 2.0 games on my Xbox 360 and make some final adjustments and then post them all on http://XnaProjects.net (and here).