Visual Studio Asset Class Generator

Visual Studio Asset Class Generator
One of the key things I learn from every game jam is what the major knots are in my work flow. The past two jams I did with Otter had a common issue: getting assets from my assets folder to the game was annoying!

I don't like to rely on strings in my code to reference things. A typo can cause a major headache, especially when referencing a path to a file that needs to be loaded. Usually I like to just keep an Assets.cs class that has a bunch of static references to various file paths. Something like this:
class Assets {

static string Asset(string str) {
string assets;
#if DEBUG
assets = "../../Assets/";
#else
assets = "Assets/";
#endif
Console.WriteLine("[ASSET] Register asset {0}.", assets + str);
return assets + str;
}

public static string ImageIcon = Asset("img/icon.png");

public static string ImagePalette = Asset("img/palette.png");
public static string ImageTile = Asset("img/tile.png");
public static string ImageTiles = Asset("img/tiles.png");

// and so on...

This makes it so I can just do something like this later:
public Image Image = new Image(Assets.ImageIcon);

Instead of having to remember that the path to the icon whenever I want to use it, I just keep a reference to it in once spot. This drastically reduces the amount of typos I could possibly hit, and it also makes it easy to bring up with auto complete and intellisense stuff.

However the process of saving out a png, then remembering the exact path to the png, and then opening up Assets.cs and adding lines to it for every new asset every single time becomes a giant pain. The more assets I have, the more complicated this becomes, and the more I'm modifying the assets folder the more annoying it gets! Back when I was using Flash I created an asset generator script to overcome this, so why not just do the same for C#? Wouldn't it be awesome to just be able to click a button in Visual Studio and have an Assets.cs generated from the files in my Assets folder?!

Download AssetClassGenerator.exe (v1.0 Windows 11kb)

This program will execute in the console and build an Assets.cs file based off of the Assets folder in your project directory. This was built with my specific use case in mind so this may not be an exact fit for your needs currently.

Set Up


The best way to get this running is in Visual Studio as an "External Tool." First download the file to somewhere you can safely keep it. It doesn't have to be in your project folder. Here I just have it in my tools folder.

Image

The next step is to hook it up with Visual Studio. In Visual Studio click on the Tools menu, and select "External Tools..." to open a dialog that looks like this:

Image


Image

Go ahead and click "Add" on the upper right. Name it whatever you want. I named it "Generate Assets.cs" for my menu. For the Command, click the "..." button and navigate to the downloaded exe.

Now the Arguments are pretty important. The first argument is the namespace that the class will use. Usually you want this to match the namespace of your project, so using "$(TargetName)" will handle this for you.

The next argument is the name of the folder to search for Assets in. In my case I keep an "Assets" folder in the root of my project folder, so it's Assets for me.

The last argument is where the Assets should be copied to. This program will copy all of the files found in your Assets folder to a folder of your choice, and in my case this is the $(BinDir), also known as the directory that Visual Studio will compile the game into. (Usually bin/Debug or bin/Release) If you choose to leave out the third argument then the program will not copy any files and just generate the class.

The program will overwrite any files of the same name in the copy to folder! Be careful not to stomp over stuff on accident.

The last thing is the Initial Directory which is the directory from which the program will run. Set this to your $(ProjectDir). The program will run as if it were inside this directory, so all paths will be relative to that. If you end up not running it from your project directory, make sure you're pointing to the proper Assets folder and Copy To folder.

I also checked the "Use Output Window" as the program will print out some debug information for you to look at and it's useful to see it if something is going wrong.

Image

That's my test project's folder structure. Now all I have to do is click on Tools in Visual Studio, go down and click on "Generate Assets.cs" and it should generate a file named Assets.cs in my project folder that looks like this:
namespace OctoberMiscTests {
public class Assets {

static string Find(string str) {
string assets;
#if DEBUG
assets = "../../Assets/";
#else
assets = "Assets/";
#endif
return assets + str;
}


public class Font {

public static string Bitmapfont = Find("Font/bitmapfont.png");
public static string FontFnt = Find("Font/font.fnt");
public static string FontPng = Find("Font/font.png");

public class cbfg {

public static string ExportedFont = Find("Font/cbfg/ExportedFont.bmp");
public static string FontData = Find("Font/cbfg/FontData.csv");

}

public class Sunset {

public static string Data = Find("Font/Sunset/Data.fnt");
public static string Image = Find("Font/Sunset/Image.png");

}

}

public class Image {

public static string EnemyLongPart = Find("Image/enemy long part.png");
public static string EnemyPart = Find("Image/enemy part.png");

public class Destroyed {

public static string EnemyLongPart = Find("Image/Destroyed/enemy long part.png");
public static string EnemyPart = Find("Image/Destroyed/enemy part.png");

}

}

}
}

Each folder becomes a class, so the folder structure is preserved as a series of classes inside classes. This makes referencing assets a breeze! Now I can do something like:
public Image Image = new Image(Assets.Image.Destroyed.EnemyLongPart);

And the auto complete stuff in Visual Studio can help me out as I type it in. So far it's been pretty magical! Note that the first time you run the generator you'll have to add the Assets.cs file to your project. The easiest way to do this I find is to have my Solution Explorer set to Show All Files which is the icon toward the right with the three files, and the file in the back is a dotted line.

Image

This will show you every file in the project folder, and you can right click on the Assets.cs file and click "Include In Project" to add it.

Image


Now you're ready to rock!

Issues


* Make sure you're setting the Copy To path to the right place, and be careful to not stomp over files on accident when using that option.

* I haven't tested this yet, but I think if you have an asset that has the same name as the folder it might cause issues.

* If you have two files of the same name but different extensions in the same folder, it will add the extension to the field name in the class.

* The class assumes that in Debug mode you want to reference the actual Assets folder in your project, and not the one copied over.

* Using a folder named "Find" or a file named "Find" may cause issues right now.

Source


The full source of version 1.0 is available here and is totally free to change, distribute, or whatever. If you have any improvements then let me know, as I'm sure there are a bunch you could make.

--

Edit: Fixed a mistake in the External Tools set up, you should actually use $(BinDir) and not $(TargetDir) for the Copy To argument.

Comments

Anonymous
Anonymous
There should be no need to change your asset path when you are in DEBUG. Are you outputting your exe to different locations?
Posted November 18th 2014 8:23 PM
Kyle
Kyle
This is a personal preference of mine. When in debug mode, I want the game to reference the assets in the project folder, not in the copied assets folder. This is so I can update the assets in the project folder and the game in debug mode can live update those assets. Otherwise in order to get that functionality I would have to edit the assets in the copied folder, then when I'm done copy that back to the core project folder. Does that make sense?
Posted November 18th 2014 10:38 PM
Anonymous
Anonymous
Makes sense, thanks for the info.
Posted November 19th 2014 8:26 PM
new comment!

Post your comment!

Name
Email
Comment