Saturday, February 17, 2007

Xna, graphics and team edition, oh my

The next step in my quest to only code my xna games in team edition was working with graphics. This proved to be a little more difficult because graphics need to be built inside Xna projects.

So, I needed to break my rules a little...
New rule:
Graphics can live in an Xna library, that is neither living in the main game solution or the GameShell exe assembly.

In Xna, graphics are just content loaded from disk built as "xnb" files, so they only need to be in the TitleLocation of the StorageContainer when your game is running (this is where the ContentManager Loads). If you look at a project containing pipeline content, you'll see an ItemGroup node:

<ItemGroup>
<Content Include="Image.jpg">
<XNAUseContentPipeline>true</XNAUseContentPipeline>
<Importer>TextureImporter</Importer>
<Processor>SpriteTextureProcessor</Processor>
<Name>spriteImage</Name>
</Content>
</ItemGroup>

So, if you wanted to, you could create an Xna library project and then just add content to it manually by copying images into a child directory and adding xml to the project file. Or, you can keep Express edition open for your graphics and build them as you need them.

So, now I have a graphics library with all my assets. Once it builds, I need to put these files in my debug directory if I want to use them, but as one of my stipulations, I didn't want to have any post build steps, so I made the following modifications to my Program.cs class in GameShell:


for (int i = argIndex; i < args.Length; i++)
{
string graphicsPath =
Path.Combine(args[i], @"bin\x86\Debug");
if (Path.IsPathRooted(graphicsPath) == false)
{
graphicsPath = Path.Combine(projectPath, graphicsPath);
}
foreach (string file in Directory.GetFiles(graphicsPath))
{
File.Copy(file, Path.Combine(debugDirectory,
Path.GetFileName(file)),
true);
}
}

Basically, I added the logic to the GameShell that any additional parameters to the application are graphic resources. If the resources aren't rooted, there are libraries inside the main project directory. So, this just goes through all those folders and copies all the files -- simple.

Still with me? This is a long one... BTW -- I have never even tried to run this on my xbox, I do all my coding on my laptop on my long ass ride home on the train so I take no responsibility for your boxes :P Also, if someone came up with a better solution, please tell me cause I'm without internet on this long ass train ride!

Yay, so now I have all the assets I need :)

Or so I thought...

I couldn't load any of these xnb resources. The content.Load was only working with resources in the bin directory GameShell :(

Reflector to the rescue...

I found this bit of code, used to determine where to find graphics:

public static string TitleLocation
{
get
{
string text1 = string.Empty;
Assembly assembly1 = Assembly.GetEntryAssembly();
if (assembly1 == null)
{
assembly1 = Assembly.GetCallingAssembly();
}
if (assembly1 != null)
{
text1 = Path.GetDirectoryName(
new
Uri(assembly1.EscapedCodeBase).LocalPath);
}
return text1;
}
}

As you can see, its using the entry assembly (or calling assembly) to determine the location of content...

So, back to my original solution with the app domains... oooo I was being clever :P

A few minutes of hacking in some appdomain code and voila, the game will only execute in the main appdomain... d'oh -- wasn't being clever after all, but I think I got that out of my system.

Returning back to my graphics copying code, I decided the simplest approach is copying the assets into the TitleLocation in Program.cs. A slight modification to the file and finally, I'm debugging my Game in Team Edition with Graphics!!!

And there was much rejoicing... yay.

I think I've put off writing some games long enough :P

No comments: