Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am making my first small mobile game in C# XNA. Lets say I have 3 screens, the main menu, options and game screen. A single game session usually lasts for 1 min, so the user will alternate frequently between the main menu and game screen. Therefore, once I load the textures for either screen, I want to keep them in memory to avoid frequent reloading. Both screens share some assets like their background textures, but differ in others. The first solution I came up with is making 2 texture factory classes, MainScreenAssetFactory and GameScreenAssetFactory, each with their own content manager, and ill store them in a globally accessible point so that they persist after either screen is destroyed. There is also a OptionsScreenAssetFactory, but that I dont want to cache it since the options screen is rarely visited.

A typical Factory would look something like this

public class MainScreenAssetFactory
{
    private readonly ContentManager contentManager;

    public MainScreenAssetFactory(IServiceProvider serviceProvider, string rootDirectory)
    {
        contentManager = new ContentManager(serviceProvider) { RootDirectory = rootDirectory };
    }

    public Texture2D ListElementBackground
    {
        get { return contentManager.Load<Texture2D>("UserTab"); }
    }

    public Texture2D ListElementBulletPoint
    {
        get { return contentManager.Load<Texture2D>("TabIcon"); }
    }

    public Texture2D LoggedOutUser
    {
        get { return contentManager.Load<Texture2D>("LoggedOutUser"); }
    }
}

Since both Main, Options and Game Screen share some common resources, instead of loading them more than once, I created another class CommonAssetTexFactory which holds the common stuff and stays in-memory during the app lifetime. For example, this class gets passed to the options screen when it is created.

However, given my small game with its few assets, I am already finding this solution cumbersome and inflexible. Changing anything would require looking to see if its already in the common factory, and if not, modifying existing factories and so on. And this is just considering textures currently, i didnt add sound files yet. I cant imagine bigger games with thousands of resources using this approach. A better idea must exist. Would someone please enlighten me?

share|improve this question
1  
What does return return actually means? Do you copy your real code? –  Petr Abdulin Oct 12 '12 at 15:36
1  
Short answer: use a method that takes a string and looks up the Texture2D in a hash table. I'll let someone else explain it out in detail... –  Ricket Oct 12 '12 at 15:36
    
I really would like to know more about the hash table thing. I thought about it but getTexture("button") is hard to refactor because of the string. For example, changing "button" to "squareButton" would require me to visit each place "button" is in. I could use an enum, but that ends up looking very similar to my current solution. If you can provide any source for me to get more details about this ill greatly appreciate it. –  user964123 Oct 12 '12 at 17:05
    
@Ricket Uhhh... ContentManager does take a string and look it up a Texture2D in a dictionary (and loads it if it doesn't find it). You don't need to write a manager layer over the top of ContentManager! –  Andrew Russell Oct 13 '12 at 4:30
    
@AndrewRussell Alright then, it sounds like this factory class is entirely unnecessary then! :) I must admit though, "Load" has that ominous sound to it, of "I'm gonna use up valuable time reading data from the slowest storage device in the system"... I'd never guess that it was caching. –  Ricket Oct 13 '12 at 10:04
show 1 more comment

2 Answers

up vote 1 down vote accepted

It sounds like your problem could be rephrased as "How do I rename assets quickly? I really like VS's refactoring support." - But how often do you rename an asset? Seriously?

I think that most games that get into the thousands of assets are highly data driven. (It's worth pointing out that - if your game isn't going to have that many assets, then you shouldn't take the same approach!)

Once you're data-driven, it should be simple enough to validate your screens/levels/maps/whatever, check the assets used, and spit out errors for missing textures, etc.

And, if you needed it, you could then add proper global rename support to your tooling.

Any assets that you load directly in your engine, and are missing, would emit a runtime error. But proper testing should shake those errors out very quickly. And they're so trivial to fix that it's not worth the additional engineering effort.


For your purposes, just load the assets by name whenever you need them. As you hopefully already know, ContentManager works as an asset cache. If an asset changes name, it's easy enough to fix by hand. "Find in files" is probably all you need.

Additionally, it's worth pointing out that, in the XNA Content Pipeline, you can change the name of a resource independently of its filename. (Select the file, press F4, it's the Asset Name property).

You shouldn't run out of resources for a game this small. But, if you need to, you can always just publically expose multiple ContentManager and load from the "right" one, allowing you to Unload() unused sets of content individually.


If you're still keen on implementing something along the lines of the "Factory" class you've shown us (strong typing, auto-complete, etc), then you should look into how "Resources" work in Visual Studio. That is: the .resx type resource you can create (Project, Add New Item, Resource File).

Note how they produce a tool-generated C# source file, containing a class with a static property for each resource.

You could do something like that yourself, if you wanted.

share|improve this answer
add comment

I think you need to rethink what problem you're trying to solve and if that problem really exists.

As far as I can tell your game is small enough to keep all assets in memory on any modern computer, have you measured your peak memory usage? (A quick and dirty way to do this is by checking the value of 'peak working set' in the task manager (be sure to select that column from the view options)). Is it only a few hundred MB? That's great! Just use one content manager, it already caches everything it loads so you don't have to worry about things being loaded twice.

If you really have a problem with keeping everything in memory you could create a content manager with it's own caching strategy, say that it evicts items if they haven't been used for sometime, however such a strategy can cause some unexpected lag if resources get evicted right before they are needed again. A better way would give you total control over when an item is present or not. A way to do this is to use resource scopes. Just as in code a variable is only valid in it's own scope ("{..."}) or a lower scope try the same approach with your game. Say the highest scope you have the menu assets, on a lower scope you have the player assets, on an even lower scope you have the current level assets, etc... Make it easy to 'pop' a scope, meaning that everything in that scope and lower scopes is evicted from memory. It is a bit similar to your current approach but more dynamic and if done right it could be easier to handle.

Consider the following logic:

Initialize Resource Manager m
m.pushScope();
Let the menu system load everything it wants
m.pushScope();
Load all the character and weapon data, in game GUI glyphs etc...
m.pushScope();
Load all level specific data.

//... player goes to level 2
m.popScope();
m.pushScope();
Load all level 2 specific data.
//...player dies and returns to menu
m.popScope();
m.popScope();
//.. Memory now only contains menu data.

//etc...

If an entity wants to know if an item is present in the cache automatically check the lowest scope first and then search bubbling up, your resource manager should handle this, the entity should never have to concern itself with this.

share|improve this answer
    
I want to mention that I am making a mobile game, not desktop. But the whole game is now 10-15MB. I would like to know how exactly would the menu load a specific texture, by using a factory like in my question? or some other method. –  user964123 Oct 12 '12 at 17:07
    
The same way it does now, by asking the content manager for that texture. Only you've replaced the content manager they use with something you've created :) (of course your class can still use the content manager class, just make sure the rest of your game uses your class) –  Roy T. Oct 12 '12 at 17:39
    
But for a big project with hundreds to thousands of assets, do they create asset factories with hundreds or thousands of properties? I think they must use another method of locating, accessing and managing assets, and that's what I am really looking to know more about. I googled a lot about the subject but surprisingly didn't find much at all... –  user964123 Oct 12 '12 at 22:55
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.