An Efficient and Lightweight Resource and Asset Manager for Games Development

The rapid increase of complexity in today’s games has made managing game resources and assets become a major challenge to game developers. This article presents a lightweight resource and asset manager that can be used to manage the resources in most games effectively. We show you how a centralized resource manager is built and used to increase the reusability of game resources. This resource manager is then used by the asset manager to create various game assets. We propose a specification that describes 3-D object (one type of game asset) that is constructed from the resource manager. We extend the specification further to allow game developers to configure the 3-D object flexibly to suit various needs. Finally, we give a few thoughts on how the asset manager can be extended further for creation of other game assets through the resource manager.

Introduction


Game development has been a challenging task since the infancy of game industry. Although one can argue that the modern technologies today have greatly simplified the game development process. But this effect is negated by the tremendous increase in the games complexity at the same time, as gamers demand a greater gaming experience on today’s high-end technologies. As a game become more complex, managing the game resources and assets become a major challenge to game developers [2].

Game developers usually create games by using high level language such as C/C++ with other libraries that are specific on certain game development tasks. For example, a game developer on PC Windows most probably will use Direct3D, a low-level graphics rendering library provided by Microsoft, on the graphics programming aspect. Some developers might opt for creating or licensing a game engine (referred as middleware sometimes) that built on the low level libraries to simplify the task further and speed up the development process. For instance, RenderWare is a renowned game engine that provides a set of high level functions that focus towards game development, i.e. load object, load image, play sound, etc. Although those game engines had greatly simplified the job of game developers, but it is still up to the game developer to use it effectively by managing the resources required by the game efficiently.

To ensure that the game resources are well managed, we need a resource manager, which serves as a centralized location for all game resources. The resources that we are referring here is the fundamental building block of games, such as 3-D objects, images, animation, sound, etc. The game developer specifies the resources that are needed by the game, and the resource manager is responsible to load them prior the game starts, and dispose them by freeing all the memory allocated by them. The resource manager will leverage on the functionalities of the underlying game engine to load and dispose each type of resource. In the game, a new game asset is constructed by consulting the resource manager, and acquiring the necessary resource from it. If the same resource is required by two game assets, the resource manager will check whether the corresponding resource can be shared. If it is, the singleton resource instance is returned. Otherwise, the resource manager will create a duplicate of the required resource, and return back the duplicated copy. Figure 1 depicts a clear relationship between the resource manager, asset manager, and the underlying game engine.

Resource Manager


The resource manager loads a list of resources specified by the game developer in a resource file written in XML form, as shown in Listing 1. We had chosen XML as the resource file format for several reasons. One is because XML is well structured and straightforward to describe each resource clearly, and we don’t need any special editor but just an ordinary text editor to view and modify it. The mandatory attributes that are associated to each resource are name, which is a unique identifier of that particular resource; src contains the filename where the resource is located; and shared is a Boolean flag to indicate whether this is a shared resource. Beside these, there are additional attributes that are specific to a particular resource, depending on the parameters that are required by the game engine to load certain resource. For example in our case, our game engine requires an integer flag specified when loading an image to indicate the type of texture filtering for that image; the number of horizontal and vertical cells in an image is required when loading an animation; and so on.

Listing 2 depicts the various methods to interface with a resource manager. The resource loading operation discussed previously is carried out by the LoadResources() function. To acquire a resource that is loaded in the resource manager, we just need to call the function GetResource(), and specifying the resource identifier and its type. The resource manager will then look up for the particular resource with the specified identifier and type. As this is the core operation of resource manager, therefore it must be able to look up for resources in minimum time. In our implementation, we use a STL hash_map for each resource type to store the resources using their names as keys. If a resource that matches the designated identifier is found, a reference to the resource is returned if it is a shared resource, or a clone of the original resource handle is returned for a nonshared resource. To clean up all the resources before the game terminates, we call to FreeResources().

The true power of resource manager is resource reusability. By pooling all the resources together in a single location, we can avoid recreating resources that are already created. For example, in a space simulator, we just need to load the explosion animation once in the resource manager, and use it at anywhere in our game whenever something explodes. On the other hand, when we associate each resource with an identifier, we actually increase the maintainability of our game as well. Imagine that if you have a major restructuring on the directory where the game resources are kept. If we are using the resource manager to acquire resources in our game, we just need to change the src attribute of each resource in our resource file. We don’t need to worry about breaking the game code result from the changes of resource files location.

Game Assets Manager


Once the resource manager has loaded the necessary resources in the game, the assets manager is responsible for creating game assets by utilizing the resources in the resource manager. Game assets here are referring to high level game entities, like actors, objects, multimedia animations, special effects, etc., which are constructed using more than one resource type. Game asset manager also abstract the game programmers away from the complexity of the internal specification and building blocks that make up a game asset. It allows the game programmers to focus more on manipulating the actual game entities where the gamers interact directly with. In the following section, we will present two game asset examples that are created by our asset manager. Both are 3-D objects that are usually used to represent game actors in 3-D games, but the second one, what we called composite 3-D object, is used for game actors that are more complex.

Basic 3-D Object

A basic 3-D object is built from a mesh object (a data structure that holds a set of vertices that makes up a 3-D model [6]), along with some images for its texture. Besides that, there are a few attributes that are used to describe the object’s appearance and characteristics. We used the XML schema in Listing 3 to define the descriptions of a basic 3-D object. To construct an object, the asset manager will read its corresponding object description file, acquire whatever resources that is required from the resource manager, and construct the object based on its descriptions.

Those elements in the basic 3-D object description file (Listing 3) with src attribute are referencing to a resource name in the resource manager. We prefix a hash (#) sign before the resource name to indicate it is really a resource name, instead of the actual resource filename. We implemented our asset manager to support both as we realized that the ability to specify absolute resource filename is sometimes useful for debugging purposes. But ultimately all resource should be reference using its name in the resource manager. Our file format also allows us to tweak the initial object transformation, material, rendering attributes, and multi-textures settings. We can even modify the texture and visibility flag of individual limb on the object. Limbs are sub-nodes, which are vertices that group together in a parent-child relationship with other nodes in a hierarchical manner [5]. Controlling the limb visibility is particularly useful in game when you need a “dummy node” on your object, i.e. a node that does not contribute visually to the object, but merely serve as a guide for positioning other objects. For example, a soldier in a war game might have an invisible dummy node on his palm, where we use it to position the weapon object that the soldier is currently holding.

Composite 3-D Object

For a more sophisticated game object, a basic 3-D object is not comprehensive enough to fully represent it. A composite 3-D object is comprised of multiple basic 3- D objects with the addition of animation control. Listing 4 shows the XML schema of a composite 3-D object description file.

A composite 3-D object must have one basic 3-D object designated as the main object. It can have several components, where each of them has a name, and is attached to a limb on the main object, along with another basic or composite object as its attachment. The component’s attachment is optional. If it is specified, its scale factor, relative offset and orientation (respect to the limb attached to) has to be set. The orientation type can be absolute, which it orients the component’s attachment exactly as it is stated; or it can also be oriented as a view billboard or axial billboard. We realized this is an important feature of a composite object, as billboarding is often used in game to represent objects that don’t have solid surfaces [7], e.g. smoke, fire, fog, vapor trails, etc. We also implemented a simple level-of-detail (LOD) control for components, as indicated by the lod attribute. The specified value is the distance where we will hide the component, if it goes beyond this distance from the viewer.

The animation control of a composite object is managed by a set of animation triggers. An animation trigger is a set of animations to be played when the trigger is activated. The animation can be keyframe animation or texture animation, which is performed on the designated component’s attachment. This feature allows simultaneous animation to be carried out together on a composite object. For example, a hunter that is firing his rifle will play a keyframe animation showing his hand recoils, at the same the blast on his rifle nozzle is indicated by a texture animation. Listing 5 shows you the main interface methods of a composite object.

Potential Enhancements


So far we had discussed about the resource manager, and how do we use it with the asset manager to create two types of 3-D object. We can further extend the functionality of asset manager for creating other game assets like special effects and multimedia animations in the same manner. Besides that, there are still plenty of rooms for improvements. For instance, we might consider combining all images, sounds, animations, mesh objects and other resource files into a single file as it is more space efficient [2]. The resource manager will then look into this file when loading resources. In addition, we can also include versioning information in the resource file as well [1]. It could be more practical to partition the resources in the resource file into a few sections, where the resource manager can choose to load a particular section only when it is needed [3]. To prevent hackers tampering with the resources of your game, or doing any reverse engineering works, we can implement a lightweight encryption proposed by Wheeler and Needham [4].

Conclusion


We had shown you a simple but practical implementation of a resource manager and asset manager where you can employ in most games development. The resource manager not only helps you to manage your game resources efficiently, but it also increases the maintainability of your game significantly. The two game assets that we had shown you can be applied very well in any 3-D games as well. The specification that we proposed is based on our experience in game development to understand the typical necessities when developing 3-D games. We had given a few thoughts to you on some possible enhancements that can be made. We believed that once these enhancements have been implemented, this can serve as an indispensable tool in the game development industry.

References


  1. B. Sousa, “File Management Using Resource Files”, Game Programming Gems 2, Charles River Media, pp. 100-104, 2001.
  2. J. Towner, “Resource Files Explained”, General Game Programming, GameDev.net, Jan 2000, http://www.gamedev.net/reference/articles/article902.asp
  3. C. Hargrove, “Code on Cob: The Butler”, loonygames, Blue’s News Publication, vol. 1.11, http://www.loonygames.com/content/1.11/cotc/
  4. D. Wheeler and R. Needham, “TEA, a Tiny Encryption Algorithm”, Cambridge University, Nov 1994, http://www.ftp.cl.cam.ac.uk/ftp/papers/djw-rmn/djw-rmntea. html
  5. D. Eberly, “Hierarchical Scene Representations”, 3D Game Engine Design: A Practical Approach to Real-Time Computer Graphics, Morgan Kaufmann, pp. 141-167, 2000.
  6. “3D Glossary”, WebReference.com, http://www.webreference.com/3d/glossary/model.html
  7. Möller. T and E. Haines, “Billboarding”, Real-time Rendering Second Edition, AK Peters, pp. 318-325, July 2002.
Write a comment