In the world of computer game development, resources refer to the external files and materials upon which a game depends. Resources include images, sounds, and other data files that a game requires in order to be played. In previous sections, a surface was loaded from a file, and therefore this image can be considered a resource. Naturally, games themselves have lots of graphics, sounds, and other data files. Consequently, games, more than most other applications, contain many different resources. Because of this, careful resource management becomes a necessary issue when developing a game.
To deal with resources, ClanLib provides a resource manager class. This class is designed to handle a collection of many resources and to share resources between different classes if required, and also to delete and remove all resources when the manager is deleted. For example, let's consider the image of a tree. A level might contain many trees, and each of these trees might look the same. If we treated each tree as an individual, the same image would need to be loaded many times, once for each tree. Naturally, this would lead to a lot of duplicated and wasted memory. Instead, the resource manager ensures all resources are loaded only once and that each resource is shared among all objects in the game. Therefore, no matter how many trees a game may contain, it will reference the same tree image in order to draw them to the display.
The resource manager is encapsulated into the class CL_ResourceManager, and this class accepts XML files that define the resources to be loaded. A resource manager can be created from an XML file as follows. This code not only creates a resource manager, but loads all the XML data into the object and configures the resources ready for use.
CL_ResourceManager *m_Manager = new CL_ResourceManager("resources.xml");
Resource XML files list all of the resources to be loaded by a resource manager and will often contain references to sounds, image files, and other sorts of media. Furthermore, they will contain additional information about how media files are to be treated and understood by ClanLib. To begin with, it is important to understand the structure of a resource XML file.
<resources> <section name="Game"> <surface name="face" file="face.png" /> </section> </resources>
Resource files have a root node called "resources." The root node may contain other nodes called "section." Sections are categories and allow resources to be grouped by category in the file. The sample file above has only one section, which is named "Game." Inside this section there may be any number of resources, of which "surface" is the type listed in this example. (We will explore another resource type, sprite, in Section 16.7.) The surface here has a name, and references a face.png file. From now on, ClanLib will recognize this resource by its combined category name and resource name, such as "Game/face." Whenever this name is used to create a surface, ClanLib will understand the image file to which we're referring.
Let's look at how many surfaces can be created from a single resource.
Say a programmer wants to create three surfaces, each with the same image, but wants to change the transparency levels of each so some are more transparent than others. Before resources were introduced, a programmer might begin to do this by creating three surfaces loaded directly from an image file, like this:
CL_Surface *Surface1 = new CL_Surface("face.png"); CL_Surface *Surface2 = new CL_Surface("face.png"); CL_Surface *Surface3 = new CL_Surface("face.png");
This leads to three duplicate images in memory because each surface has caused face.png to be loaded separately. A better method is to use resources. Resource managers ensure no two resources are loaded twice and allows a single resource loaded in memory to be shared between each surface. Using the sample XML from the previous sections, three surfaces can be created from a resource as follows:
CL_ResourceManager *Manager = new CL_ResourceManager("resources.xml"); CL_Surface *Surface1 = new CL_Surface("Game/face", Manager); CL_Surface *Surface2 = new CL_Surface("Game/face", Manager); CL_Surface *Surface3 = new CL_Surface("Game/face", Manager);