The AddUnloadMethod allows you add custom logic to be executed when a ContentManager is unloaded. This is most often used to null-out static references to content contained in a particular ContentMangaer. This functionality is used heavily in Glue generated code, but it can also be used to null-out static objects in custom code.
The following code shows how to create a static Texture2D in custom code, and how to properly unload it. This code would be part of the custom code of a Screen or Entity. For this example we'll assume an Entity called Character.
If you are using the FlatRedBall Editor, you may not have to directly interact with the ContentManager object. For example, if you add a .png file to the FlatRedBall Editor, it will automatically load the file in generated code using the ContentManager. However, if you would like to work with content in code, or if your game requires advanced handling of content then you may need to work with the ContentManager in custom code.
Computer memory can exist in a variety of locations: On the hard disk, in RAM, or even on the hard disks of other computers which you can access through the Internet (as you are currently doing when viewing this page). Not all types of memory can be accessed with the same speeds. Getting data through the Internet is very slow compared to data that is sitting on your local hard disk, and accessing data on the hard disk is much slower than accessing data in RAM. When the same data needs to be accessed multiple times, making a copy of it and moving it to faster memory can help improve performance. Content such as Textures and Models are copied from the hard disk to RAM to speed up future access to this memory - as well as to prevent duplicate memory in RAM.
Content managers simplify the loading of new assets as well as help organize existing assets. Content managers in FlatRedBall store references to a variety of assets. The most common type of reference held by content managers is of type Texture2D. Any FlatRedBall method which can potentially load a Texture2D works with FlatRedBall's internal content managers. Content managers are also useful for organizing data. Any data which has the same lifespan - such as textures, geometry, and sound files in a given level - should belong to the same content manager. When the level ends, simply removing that content manager unloads all memory associated with the level. Content managers make memory management and game state changes much easier.
This method has an overload which allows the content manager to be specified. Calling the one-argument version is the same as passing "Global" as the second argument:
The Global content manager is used by default by all methods which load Texture2D's when a content manager is not explicitly supplied in the argument list. To specify a different content manager, simply provide the string of the new name - there is no need to instantiate any instances as this is all handled internally. Loading the same asset using the same content manager does not result in multiple copies of the asset in memory and the hard disk is only accessed once. The following code creates only one copy of the redball.bmp texture in memory.
While the following creates three separate copies of the redball.bmp texture and also the hard disk is accessed three times:
Or another way to look at it is:
The following code simulates the creation and destruction of 3 levels. Levels can be loaded and unloaded by pressing the 1, 2, and 3 keys. The text object which is created displays the loaded content and the Sprites themselves display the loaded Sprites.
Even if you understand the concept that content managers can be thought of as a "bucket of asset", you may be wondering which content manager to put assets in. The following lists a few conditions to help you decide.
Are you just debugging? If you are writing code that will not ship with the final game, or if you're just testing something out, then it really doesn't matter what you use. Passing any string will create a new content manager to store the asset. Of course, creating content managers without paying attention to their names can create a buildup of assets if content managers are not cleaned up properly.
Content managers provide functionality for organizing and caching game assets. They can be thought of as a "bucket of assets". When you create an asset through the Content Manager, you give it a name (usually its file name) and decide which Content Manager it goes into. Later if the same name appears, the FlatRedBall Engine will return a reference to that asset instead of loading it from disk. Although MonoGame has a content manager class by the qualified name of Microsoft.Xna.Framework.Content.ContentManager, you do not have to ever explicitly interact with this class when using FlatRedBall. Instead, you simply work with content managers through the class.
If you have programed a FlatRedBall application which displays a texture (such as the red ball texture on a ) then you have worked with content managers - although you may not realize it. Any method which takes a string file name for a Texture2D also takes a string for a content manager name. Some methods have overloads which do not require a content manager string argument, but those simply use the default "Global" content manager. You may be familiar with the AddSprite method:
Is your content going to live forever? You may be creating a game with a particular object (such as a or a second ) that you never want to unload. If this is the case, then you may want to use the global content manager. You can use the FlatRedBallServices.GlobalContentManager property as the value passed to any method that accepts a content manager.
Are you using ? The base class defines a property called ContentManagerName. If the object that you're creating should be destroyed when the is destroyed, then you should use the Screen's ContentManagerName.
Are you creating an object which will be destroyed at some time in the future? If you are not using but still want to perform your own content management (and destruction) then you should place your object in the same content manager as other objects which will be destroyed at the same time. Of course, we encourage the use of as they have been created for this reason and they simplify the management of assets.
- Shows an example of how Content Managers cache content.
- AddDisposable can be used to add IDisposables to Content Managers.
- Discusses the purpose of having multiple content managers.
FlatRedBall supports having any number of ContentManagers living concurrently. This section will explain some situations where multiple content managers may be useful.
Multiple content managers may be used if two content managers can exist at the same time, usually for async or time-sliced loading. For example, consider a game where the user transitions from one screen to another. The content managers lay live as follows:
Content managers can also be used to provide transitions between Screens - this is typically how Loading screens operate:
Content managers can be used if you have content which has a predefined lifespan and will be removed before the current Screen is destroyed. This may look like this:
Note that deleting the object may not help much to reduce maximum memory usage - the peak will likely be hit while both content managers are alive.
If you need to load and unload individual assets, you may consider using multiple content managers. This is useful for tools. Keep in mind that if you are performing from-file content loading, you do not necessarily need to even use content managers. The ContentManager class is intended to be used as a convenient way to cache, group, and unload a collection of content, so situations where you load and unload individual files may not benefit from working with a ContentManager.
The IsAssetLoadedByName method returns whether a file of a given type is already loaded and stored in RAM by the given ContentManager.
The following code can be used to check if a file Background.png is loaded as a Texture2D in the current screen's content manager:
IsAssetLoadedByDetail processes the assetName parameter before checking if it has been loaded. Specifically, the following modifications are made:
If the argument is relative (such as content/background.png ), then it is converted to an absolute path (such as c:/MyGame/bin/debug/content/background.png ).
The file is standardized using the FileManager.Standardize method.
The content type is appended to the file name. This allows the same file to be loaded into multiple types.
For example, loading "content\Background.png" may result in the string "c:/folder/content/background.pngTexture2D" being stored in the ContentManager.
The Load method is used to obtain a reference to an object which is created from a file on disk. Common examples of are Texture2D (usually from a .png file), SoundEffect (usually from a .wav file), and AnimationChainList (usually from a .achx file). The Load method caches a file when successfully loaded, and subsequent calls to the Load method will return the cached reference.
The Load method can be used to load a Texture2D from an image file.
This exception can occur if your game is attempting to load a texture that is larger than is supported on the hardware running your game. For example, at the time of this writing many Android devices support 4096x4096 textures, but phones which only support 2048x2048 are still somewhat common. If the phone does not support loading the texture due to dimensions the app will throw a System.InvalidOperationException .
The LoadFromGlobalIfExists is a static variable in the ContentManager class which controls whether FlatRedBall will search in the Global content manager for content even if a file is being loaded from a non-global content manager. The default value is true.