Sun Rise
Sun Rise

Reputation: 21

Can we unload a specific texture? MonoGame

I know you can unload all the content in a monogame project, but I am wondering if it is possible to unload a specific texture, for example, after a level.

I have a texture that I modify using .GetData and .SetData, and I reuse this texture in other levels as well as when the player dies, however when I use it in another repeated level, or when I restart the current level, the texture remains in its modified state, rather than its original. If I unload all of the content then the texture gets modified and resets at the start of the level, however I lose some of my other content.

So the real question is, can you unload a specific texture without unloading all of the content?

Any help would be appreciated :)

Upvotes: 2

Views: 2145

Answers (3)

José Gomes
José Gomes

Reputation: 55

I believe that as of 2023 (don't know for how long this has been a thing) you can unload a specified resource by calling Texture.Dispose() and adding an Unload(string name) method to your custom content manager like this:

internal void Unload(string name)
    {
        LoadedAssets.Remove(name);
    }

At least this is working on my project and allows a Texture to be reloaded.

EDIT: Monogame base content manager has a List<IDisposable> disposableAssets which cannot be accessed via subclasses. Even if you use my method you will end up with references to the original textures in that list. Keep that in mind!

Upvotes: 1

vgru
vgru

Reputation: 51292

The problem with simply disposing objects is that there is not a way for other parts of your code to know whether an object has been disposed. ContentManager only provides the Unload() method, which unloads and disposes all resources, and you cannot simply create your own derived implementation because its internal list of disposable assets is private (not protected). If you implemented your own Unload(string asset) method, this private list would still hold a reference to your asset and then try to dispose it again when the ContentManager is disposed (disposing twice should work if it's implemented correctly by the resource class, but if nothing else, you are preventing GC to reclaim this memory).

The only way to implement a ContentManager.Unload(string assetName) method would therefore be to change the MonoGame source directly.

Common approach is slightly easier: simply use multiple ContentManager instances, i.e. a shared ContentManager instance in the Game class, and a separate private ContentManager instance in each GameScreen (or whatever you are using to organize your game), which is disposed whenever you switch scenes.

For async content loading, I have also implemented a custom async content manager for my apps, which queues the loading job on first access into a separate thread and returns null on subsequent calls until the resource is fully loaded.

Upvotes: 2

BornToGrill
BornToGrill

Reputation: 60

To answer your question instead of disposing of the entire content manager, you can dispose the texture object itself.

Texture2D MyTexture = Content.Load<Texture2D>("Texture.png");

Your content manager ( "Content" ) now has this texture loaded.

MyTexture.Dispose();

By disposing the texture object rather than the entire content manager only the specified texture will be "disposed". Though the texture will only be unloaded, the reference in the content manager will not be removed.

As pointed out by craftworkgames the reference to the texture object will remain in the content manager which means it can't be reloaded using Content.Load<>().

I think the approach you're looking for is not disposing the texture but just overwriting it when a level resets. When the level resets you just call the Content.Load method on the same texture object again. This will load the default texture back in overwriting your modified one.

Upvotes: -1

Related Questions