Sign in to follow this  
Prot

How to pass content through the project's structure efficiently?

Recommended Posts

Prot    541

Hi there,

 

so following situation. I have a project which is structured something like this.

 

Game1 -> GameManager -> Module1-X (so multiple instances)

 

During runtime units are being spawned in each instance of the Module class. Those Units require spritesheets for animation. Let us say each unit has a "Move", "Attack" and "Die" state, each using a individual spritesheet. This makes three Texutre2D instances per unit and with 5 different units this adds up to 15 different Texture files. Those are being passed to the unit's constructor on creation.

 

As I am loading those textures in Game1's LoadContent method I have to pass them the entire way to the Module class which then uses those textures to instaciate units.

 

Game1.LoadContent(15x textures) -> GameManager(15x textures) -> Module(15x textures) -> Unit(3x textures)

 

Imo this has several disadvantages:

  1. As far as I can judge all those 15 textures are being held in memory of the Module classes the entire time. I would like to avoid that.
  2. Also passing 15 textures through the project's entire structure makes the classes unreadable and ugly.
  3. I've got the overall feeling that this is not the way things should be done here.

In order to avoid problem #2 I created a class, its only purpose is to hold all textures that are needed in Module.cs. I called the class AnimationCollection. It holds Texture2D variables and the according getters and setters. So now my Project looks like this.

 

Game1.LoadContent(new AnimationCollection(15x textures)) -> GameManager(AnimationCollection) -> Module(AnimationCollection) -> Unit(AnimationCollection)

 

While this does seem to solve problem #2 the other problems remain.

 

Are there other options on how to handle this problem? I could think of something like loading all content in the Module Class itself, but I never saw this before. I always load my stuff in Game1.LoadContent().

 

Any ideas, suggestions or expert knowledge is highly appreciated.

 

Thanks in advance!

Edited by Prot

Share this post


Link to post
Share on other sites
Ashaman73    13715

Usally you use a resouce manager for handling shared resources like textures. Here's the basic setup of a resource manager (pseudo-code):

class TextureResourceManager : 
{
 HashMap<String,Texture> mTextures;
 HashMap<String,Integer> mCounters;
 TextureResourceManager () {..init members ...}

  Texture requestTexture(String id) {
    // texture already present ?
    Texture result = mTextures.get(id);
    // create new ?
    if(result==NULL) {
       result = loadTexture(id);
       mTextures.put(id,result);
       mCounters.put(id,0);
    }

   // increase counter by one
   mCounters.put(id,mCounters.get(id)+1);
   return result;
  }

  void releaseTexture(Texture tex) {
   // get id
   String id = tex.getId();
   // reduce counter
   int counter = mCounters.get(id)-1;
 
   // release shared resource ?
  if(counter==0) {
     ..free texture resources...
    mTextures.remove(id);
    mCounters.remove(id);
    } else {
      // still used by others
      mCounters.put(id,counter );
   }
 }
}


Share this post


Link to post
Share on other sites
Brain    18906
I agree with ashaman except I wouldn't load on demand, rather preload all textures on construction into the map. This way there is no delay when first displaying that texture. On xbox 360 for example disk access can be dog slow, which can mean a stuttery game for the first few seconds if you load on demand.

Share this post


Link to post
Share on other sites
PKLoki    1492

I'd also question the wisdom of having so many small textures. Why not combine all frames of animation for one unit into a single texture? Or even all frames for multiple units in one texture? Reducing the number of textures will improve your ability to batch draw calls, with improved performance. In the limit, if every sprite in your game can fit in a single texture then you'll never need to switch textures at all. That's unlikely of course, and deciding what to combine into textures for maximum benefit is very much dependent on your content and how it's used. But you can potentially gain in both performance and simplicity by merging assets.

Share this post


Link to post
Share on other sites
PKLoki    1492

Oh, and since this is for XNA you might look into using the SpriteFont generator for sprites generally. I don't know what it's like nowadays in XNA but I think the one in the native DirectXTK is basically the same. You can coopt the same functionality to pack any sprites you like into a 'spritefont' file, they don't have to be letters. Then you draw single frames by using the appropriate single-character 'string' for the sprite in question. It's a clunky API for the task because it annoyingly assumes you'll be drawing text, but it'll do the job effectively and saves you having to write your own sprite-sheet packing tools.

Share this post


Link to post
Share on other sites
phil_t    8084


In order to avoid problem #2 I created a class, its only purpose is to hold all textures that are needed in Module.cs. I called the class AnimationCollection. It holds Texture2D variables and the according getters and setters. So now my Project looks like this.

 

That seems reasonable.

 


Are there other options on how to handle this problem? I could think of something like loading all content in the Module Class itself, but I never saw this before. I always load my stuff in Game1.LoadContent().

 

If Module is a DrawableGameComponent, then it could load the textures in its LoadContent 

 


As far as I can judge all those 15 textures are being held in memory of the Module classes the entire time. I would like to avoid that.

 

Why? All you're storing is references to the textures. The textures obviously have to be loaded, since they're being used to draw the Units. The memory impact of 15 texture references is pretty insignificant.

Share this post


Link to post
Share on other sites
CC Ricers    1491

Keep in mind that textures loaded by the same ContentManager object stay cached, so all your game Units that use the same texture will point to the same data in memory, as phil_t has mentioned. Your custom Module class just keeps references to the data loaded by ContentManager.

 

I agree with ashaman except I wouldn't load on demand, rather preload all textures on construction into the map. This way there is no delay when first displaying that texture. On xbox 360 for example disk access can be dog slow, which can mean a stuttery game for the first few seconds if you load on demand.

 

Yes, and this was true also because calling the GC to re-allocate megabytes of data was more expensive, and creates more latency. It is ideal to do this in transitional parts of your game such as a loading screen.

 

On most PC's it's not as big of a deal but it's still a good practice to pool your resources. Sometimes creating new data on demand can't be avoided, as with procedurally generated content. But you can still pre-allocate some data and keep re-writing to it as new content is generated.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this