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'm making a SpaceWar!-esque game using XNA. I want to limit my ships to 5 active bullets at any time. I have a Bullet DrawableGameComponent and a Ship DrawableGameComponent. My Ship has an array of 5 Bullet.

What is the best way to manage the Bullet textures? Specifically, when should I be calling LoadTexture? Right now, my solution is to populate the Bullet array in the Ship's constructor, with LoadTexture being called in the Bullet constructor. The Bullet objects will be disabled/not visible except when they are active. Does the texture really need to be loaded once for each individual instance of the bullet object? This seems like a very processor-intensive operation.

Note: This is a small-scale project, so I'm OK with not implementing a huge texture-management framework since there won't be more than half a dozen or so in the entire game. I'd still like to hear about scalable solutions for future applications, though.

share|improve this question

3 Answers 3

up vote 7 down vote accepted

First of all: how you do it doesn't really matter. Just do the very simplest thing that could possibly work. My current favourite way is with static methods in each class (ie: bullet, ship), like this:

static Texture2D myTexture, myOtherTexture;
// Call me from Game.LoadContent:
public static void LoadContent(ContentManager content) { content.Load /* ...etc */ }

(This is perfectly fine for simple games where you only have a single ContentManager instance and never call Unload.)

Being able to toss in simple systems like this is one reason why I don't think it's a good idea to use DrawableGameComponent.

As has been mentioned a couple of times: XNA's ContentManager will share instances of loaded content (like textures). So after the first time you load it, subsequent loads will give you back the same texture with no cost for loading.


Anyway - it doesn't really matter how you load your content. What matters (and what you are asking) is when?

The answer to that is simple: Load your textures when your game starts! (Or behind loading screens or other the-game-isn't-animating screens if necessary.) If you cannot do this, the correct solution is to load your textures in a worker thread.

When you load a texture (a synchronous operation - it blocks the calling thread), you take a hit pulling the data from disk, a hit to decode it, a hit to send it to the GPU, and a hit if you trigger the garbage collector (blocks all threads, and is especially bad on Xbox 360).

In terms of the game loading, loading a texture is a very fast operation. In terms of the 16ms you have to calculate and render each frame at 60FPS, loading a texture is agonisingly slow.


Bill, in comments, asked for some resources on ContentManager. I am obviously biased, but I think some of my answers (including this one) contain some pretty good information and hint at some best practices:

And one from XNA lead Shawn Hargreaves: If ContentManager doesn't suit your resource-management needs, you should derive from ContentManager and override Load. This way you can implement whatever asset tracking you like, without making ugly custom wrappers.

share|improve this answer
    
Thanks for the extra info; accepted. –  Bill Mar 7 '11 at 0:51

If the texture is always the same then you should load the texture once in the game life, for example in the Ship class once it´s LoadContent is called.

***I´m not sure, but I think XNA loads the texture once, and the other calls to the load method will just use the memory loaded texture. Even if that is true, I think calling that method once is beter.

share|improve this answer
    
What do you mean "always the same"? Each bullet will use the same texture, and this texture does not change. So I only need to load it once and store a reference to it, then I can pass it to each of my Bullet objects? –  Bill Mar 4 '11 at 6:36
    
He means what ZorbaTHut is saying in how GetTexture will cache the texture. XNA manages this automatically for you, so just call Content.Load<Texture>(textureName) in the LoadContent() method of your DrawableGameComponent, and XNA will handle the rest. If you are concerned about pre-loading the texture, then you should call Content.Load<Texture>(textureName) at the point at which you wish the texture to be loaded. This may be useful if you dynamically instantiate a DrawableGameComponent mid-game which uses a new texture and wish to eliminate the risk of the possibile of garbage collection. –  michael.bartnett Mar 4 '11 at 9:56

The simplest texture manager has one function: GetTexture. GetTexture checks its cache for a texture. If the texture isn't cached, it loads the texture. Then it returns the texture. Kapow! Done!

That is sufficient for most small-scale indie games I've seen. You just don't have enough content for this to ever be a problem.

One downside is that this can result in loading hiccups during gameplay. Quick fix: just call GetTexture with all the textures you expect to use during a "loading" section. Another possible fix: when you "load" a texture, hand a functional blank texture handle back, then start loading in the data asynchronously in the background (in another thread or with asynchronous file loading calls) and fill it in once it's done. This way you avoid the load hitches, but things can look a bit weird until textures are filled in. If you want to implement this, I'd recommend a GetTextureAsync function to call when asynchronous loading is acceptable (which in my experience will be only a few places, but those places may account for the majority of the textures in your game.)

Another downside is that you will, eventually, keep all the textures in your game in memory at once. This can also be easy to fix - if your game is divided into levels, just clear the entire cache between levels and reload everything. A somewhat more complex solution is to throw away textures after they've been unused for some number of seconds. This works great for large streaming worlds with unknown resources needed at each point (like MMOs - you never know what armor you're going to see next) but it does mean there's some lag between when a texture is unneeded and when the memory is actually freed.

If you want a more complex texture manager, you can start having formal concepts of blocks of textures that need to be preloaded. Each level can have a texture corpus, and when you change levels, you explicitly throw away the old corpus and load in the new one. Couple this with on-demand loading for unexpected textures, and a delay for deallocating those, and you're pretty much set for quiet some time.

As an example of this, in a game in a large contiguous world you might break the world into areas, then come up with a corpus for each area. Load textures for all adjacent areas to the player while throwing away textures from further away. (With refcounting, of course - if every area uses "grass", then there's no reason to store multiple copies of "grass".)

But meanwhile, back in reality, you'll probably be just fine with GetTexture. :)

share|improve this answer
    
Can you comment as to whether each entity needs to load the texture? (i.e., 5 Bullet = 5 LoadTexture calls) or do I only need to load once, then I can share that for all things that will use that texture? –  Bill Mar 4 '11 at 6:24
    
If you go through a GetTexture manager, you'll end up with five GetTexture calls and one LoadTexture call. I'm assuming this all works the same as OpenGL, however - I've never used XNA itself - but I'd find it quite unbelievable that you couldn't re-use textures. That's kind of a fundamental of modern graphics :) –  ZorbaTHut Mar 4 '11 at 8:54
1  
XNA's built-in ContentManager already reuses loaded content, including textures. Caching, if you like. Don't implement a caching layer over the top! To do fancy stuff like granular caching and unloading between levels, create multiple instances of ContentManager or customise it. –  Andrew Russell Mar 4 '11 at 11:47
    
@Andrew Russell Do you have any links to good resources discussing the ContentManager and best practices when using it? –  Bill Mar 4 '11 at 15:29
    
@Bill Rather than try and squash the info into a comment, I've added a bit more information to the end of my answer. –  Andrew Russell Mar 6 '11 at 13:47

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.