Resource Manager

Exclusive offer: get 50% off this eBook here
Developing Mobile Games with Moai SDK

Developing Mobile Games with Moai SDK — Save 50%

Learn the basics of Moai SDK through developing games with this book and ebook

$17.99    $9.00
by Francisco Tufró | September 2013 | Games Open Source

This article created by Francisco Tufr? Developing Mobile Games with Moai SDK discusses the creation of an entity that handles all of our assets in the game. We’ll call itResourceManager. We’ll see how to create one that allows you to add images, fonts, and sounds to your games.

The main idea behind the resource manager is to cache assets that we’ll use more than once and to have a centralized and abstracted way to create assets.

(For more resources related to this topic, see here.)

Resource definitions

In order to be able to define resources, we need to create a module that will be in charge of handling this. The main idea is that before calling a certain asset through ResourceManager, it has to be defined inResourceDefinitions. In this way, ResourceManager will always have access to some metadata it needs to create the asset (filenames, sizes, volumes, and so on).

In order to identify the asset types (sounds, images, tiles, and fonts), we will define some constants (note that the number values of these constants are arbitrary; you could use whatever you want here). Let’s call them RESOURCE_TYPE_[type] (feel free to use another convention if you want to). To make things easier, just follow this convention for now since it’s the one we’ll use in the rest of the book. You should enter them in main.lua as follows:

RESOURCE_TYPE_IMAGE = 0

RESOURCE_TYPE_TILED_IMAGE = 1

RESOURCE_TYPE_FONT = 2

RESOURCE_TYPE_SOUND = 3

If you want to understand the actual reason behind these resource type constants, take a look at the load function of our ResourceManager entity in the next section.

We need to create a file named resource_definitions.lua and add some simple methods that will handle it.

Add the following line to it:

module ( “ResourceDefinitions”, package.seeall )

The preceding line indicates that all of the code in the file should be treated as a module function, being accessed through ResourceDefinitions in the code. This is one of many Lua patterns used to create modules.

If you’re not used to the Lua’s module function, you can read about it in the modules tutorial at http://lua-users.org/wiki/ModulesTutorial.

Next, we will create a table that contains these definitions:

local definitions = {}

This will be used internally and is not accessible through the module API, so we create it using the keyword local.

Now, we need to create the setter, getter, and unload methods for the definitions.

The setter method (called set) stores the definition parameter (a table) in the definitions table, using the name parameter (a string) as the key, as follows:

function ResourceDefinitions:set(name, definition)

definitions[name] = definitionend

The getter method (called get, duh!) retrieves the definition that was previously stored (by use of ResourceDefinitions:set ()) using the name parameter as the key of the definitions table, as follows:

function ResourceDefinitions:get(name) return definitions[name]end

The final method that we’re creating is remove. We use it to clear the memory space used by the definition. In order to achieve this we assign nil to an entry in the definitions table indexed by the name parameter as follows:

function ResourceDefinitions:remove (name) definitions[name] = nilend

In this way, we remove the reference to the object, allowing the memory to be released by the garbage collector. This may seem useless here, but it’s a good example of how you should manage your objects to be removed from memory by the garbage collector. And besides this, we don’t know information comes in a resource definition; it may be huge, we just don’t know.

This is all we need for the resource definitions. We’re making use of the dynamism that Lua provides. See how easy it was to create a repository for definitions that is abstracted from the content of each definition. We’ll define different fields for each asset type, and we don’t need to define them beforehand as we probably would have needed to do in C++.

Resource manager

We will now create our resource manager. This module will be in charge of creating and storing our decks and assets in general. We’ll retrieve the assets with one single command, and they’ll come from the cache or get created using the definition.

We need to create a file named resource_manager.lua and add the following line to it:

module ( “ResourceManager”, package.seeall )

This is the same as in the resource definitions; we’re creating a module that will be accessed using ResourceManager.

ASSETS_PATH = ‘assets/’

We now create the ASSETS_PATH constant. This is the path where we will store our assets. You could have many paths for different kinds of assets, but in order to keep things simple, we’ll keep all of them in one single directory in this example. Using this constant will allow us to use just the filename instead of having to write the whole path when creating the actual resource definitions, saving us some phalanx injuries!

local cache = {}

Again, we’re creating a cache table as a local variable. This will be the variable that will store our initialized assets.

Now we should take care of implementing the important functionality. In order to make this more readable, I’ll be using methods that we define in the following pages. So, I recommend that you read the whole section before trying to run what we code now. The full source code can be downloaded from the book’s website, featuring inline comments. In the book, we removed the comments for brevity’s sake.

Getter

The first thing we will implement is our getter method since it’s simple enough:

function ResourceManager:get ( name ) if (not self:loaded ( name )) then self:load ( name ) end return cache[name] end

This method receives a name parameter that is the identifier of the resource we’re working with. On the first line, we call loaded (a method that we will define soon) to see if the resource identified by name was already loaded. If it was, we just need to return the cached value, but if it was not we need to load it, and that’s what we do in the if statement. We use the internalload method (which we will define later as well) to take care of the loading. We will make this load method store the loaded object in the cache table. So after loading it, the only thing we have to do is return the object contained in the cache table indexed by name.

One of the auxiliary functions that we use here is loaded. Let’s implement it since it’s really easy to do so:

function ResourceManager:loaded ( name ) return cache[name] ~= nil end

What we do here is check whether the cache table indexed by the name parameter is not equal to nil. If cache has an object under that key, this will return true, and that’s what we were looking for to decide whether the object represented by the name parameter was already loaded.

Loader

load and its auxiliary functions are the most important methods of this module. They’ll be slightly more complex than what we’ve done so far since they make the magic happen. Pay special attention to this section. It’s not particularly hard, but it might get confusing. Like the previous methods, this one receives just the name parameter that represents the asset we’re loading as follows:

function ResourceManager:load ( name )

First of all, we retrieve the definition for the resource associated to name. We make a call to the get method from ResourceDefinitions, which we defined earlier as follows:

local resourceDefinition = ResourceDefinitions:get( name )

If the resource definition does not exist (because we forgot to define it before), we print an error to the screen, as follows:

if not resourceDefinition then

print(“ERROR: Missing resource definition for “ .. name )

If the resource definition was retrieved successfully, we create a variable that will hold the resource and (pay attention) we call the correct load auxiliary function, depending on the asset type.

else local resource

Remember the RESOURCE_TYPE_[type] constants that we created in the ResourceDefinitions module? This is the reason for their existence. Thanks to the creation of the RESOURCE_TYPE_[type] constants, we now know how to load the resources correctly. When we define a resource, we must include a type key with one of the resource types. We’ll insist on this soon. What we do now is call the correct load method for images, tiled images, fonts, and sounds, using the value stored in resourceDefinition.type as follows:

if (resourceDefinition.type == RESOURCE_TYPE_IMAGE) then

resource = self:loadImage ( resourceDefinition )

elseif (resourceDefinition.type == RESOURCE_TYPE_TILED_IMAGE) then

resource = self:loadTiledImage ( resourceDefinition )

elseif (resourceDefinition.type == RESOURCE_TYPE_FONT) then

resource = self:loadFont ( resourceDefinition )

elseif (resourceDefinition.type == RESOURCE_TYPE_SOUND) then

resource = self:loadSound ( resourceDefinition ) end

After loading the current resource, we store it in the cache table, in an entry specified by the name parameter, as follows:

-- store the resource under the name on cache cache[name] = resource

endend

Now, let’s take a look at all of the different load methods. The expected definitions are explained before the actual functions so you have a reference when reading them.

Images

Loading images is something that we’ve already done, so this is going to look somewhat familiar.

In this book, we’ll have two ways of defining images. Let’s take a look at them:

{

type = RESOURCE_TYPE_IMAGE

fileName = “tile_back.png”,

width = 62,

height = 62,

}

As you may have guessed, the type key is the one used in the load function. In this case, we need to make it of type RESOURCE_TYPE_IMAGE.

Here we are defining an image that has specific width and height values, and that is located at assets/title_back.png. Remember that we will use ASSET_PATH in order to avoid writing assets/ a zillion times. That’s why we’re not writing it on the definition.

Another useful definition is:

{

type = RESOURCE_TYPE_IMAGE

fileName = “tile_back.png”,

coords = { -10, -10, 10, 10 }}

This is handy when you want a specific rectangle inside a bigger image. You can use the cords attribute to define this rectangle. For example, we get a square with 20 pixel long sides centered in the image by specifying coords = { -10, -10, 10, 10 }.

Now, let’s take a look at the actual loadImage method to see how this all falls into place:

function ResourceManager:loadImage ( definition ) local image

First of all, we use the same technique of defining an empty variable that will hold our image:

local filePath = ASSETS_PATH .. definition.fileName

We create the actual full path by appending the value of fileName in the definition to the value of the ASSETS_PATH constant. if checks whether the coords attribute is defined:

if definition.coords then

image = self:loadGfxQuad2D

( filePath, definition.coords )

Then, we use another auxiliary function called loadGfxQuad2D. This will be in charge of creating the actual image. The reason why we’re using another auxiliary function is that the code used to create the image is the same for both definition styles, but the data in the definition needs to be processed differently. In this case, we just pass the coordinates of the rectangle.

else

local halfWidth = definition.width / 2

local halfHeight = definition.height / 2

image = self:loadGfxQuad2D(filePath,

{-halfWidth, -halfHeight, halfWidth, halfHeight} )

If there were no coords attribute, we’d assume the image is defined using width and height. So what we do is to define a rectangle that covers the whole width and height for the image. We do this by calculating halfWidth and halfHeight and then passing these values to theloadGfxQuad2D method. Remember the discussion about the texture coordinates in Moai SDK; this is the reason why we need to divide the dimensions by 2 and pass them as negative and positive parameters for the rectangle. This allows it to be centered on (0, 0). After loading the image, we return it so it can be stored in the cache by the load method:

end

return image

end

Now the last method we need to write is loadGfxQuad2D. This method is basically to display an image as follows:

function ResourceManager:loadGfxQuad2D ( filePath, coords )

local image = MOAIGfxQuad2D.new ()

image:setTexture ( filePath )

image:setRect ( unpack(cords) )

return image

end

Lua’s unpack method is a nice tool that allows you to pass a table as separate parameters. You can use it to split a table into multiple variables as well:

x, y = unpack ( position_table )

 

What we do here is instantiate the MOAIGfxQuad2D class, set the texture we defined in the previous function, and use the coordinates we constructed to set the rectangle this image will use from the original texture. Then we return it so loadImage can use it.

Well! That was it for images. It may look complicated at first, but it’s not that complex.

The rest of the assets will be simpler than this, so if you understood this one, the rest will be a piece of cake.

Developing Mobile Games with Moai SDK Learn the basics of Moai SDK through developing games with this book and ebook
Published: March 2013
eBook Price: $17.99
Book Price: $29.99
See more
Select your format and quantity:

Tiled images

Another useful type of asset is tiled images. In gaming, we usually use tiled images to load a single texture and use fragments of it for specific purposes (for example, animations can be achieved using this technique). This will be handy in our game Concentration, to define which tiles should be placed in the matrix.

The tiled image definition is as follows:

{

type = RESOURCE_TYPE_TILED_IMAGE,

fileName = ‘tiles.png’,

tileMapSize = {3, 2}

}

This is basically the same as the normal image, but we need to add tileMapSize and remove width and height. This table will be unpacked as the parameters for MOAITileDeck2D:setRect (check it out at http://getmoai.com/docs/class_m_o_a_i_tile_deck2_d.html#a504da8814f74038af9d453ebbc7fd5ae). In this case, it says that the tile map has three columns and two rows, giving a total of six tiles.

loadTiledImage is as follows:

function ResourceManager:loadTiledImage ( definition )

local tiledImage = MOAITileDeck2D.new ()

local filePath = ASSETS_PATH .. definition.fileName

tiledImage:setTexture ( filePath )

This is essentially the same as what we did with the image. We append fileName to ASSETS_PATH to get the final texture filePath.

tiledImage:setSize ( unpack (definition.tileMapSize) )

The only real difference is that we unpack the tileMapSize attribute to pass it to setSize. You may use all of the possible parameters that can be passed to setSize; these are explained in the Moai SDK API documentation.

-- return the final image

return tiledImage

end

And this is pretty much the same as for the normal image. We return tiledImage to be used later.

Fonts

Fonts are easier, and the definition is as follows:

{

type = RESOURCE_TYPE_FONT,

fileName = ‘myfont.ttf’,

glyphs = “0123456789”,

fontSize = 26,

dpi = 160

}

The specific attributes that we have here, besides the type and the filename, are glyphs (these are the characters that we will use; in this example, we only use the numbers from 0 to 9), fontSize, and dpi for font.

The loadFont method is as follows:

function ResourceManager:loadFont ( definition )

local font = MOAIFont.new ()

local filePath = ASSETS_PATH .. definition.fileName

font:loadFromTTF ( filePath, definition.glyphs,

definition.fontSize, definition.dpi )

return font

end

The whole method is basically the same as the other loaders; the differences are that we use MOAIFont as the class, and we use loadFromTTF with the necessary parameters to initialize it.

Sounds

The definition for sounds is as follows:

{

type = RESOURCE_TYPE_SOUND,

fileName = ‘sugarfree.mp3’,

loop = true,

volume = 0.6

}

The specific attributes for sounds are loop (whether the sound should loop constantly or not) and volume (the initial volume for it).

Moai SDK comes with support for two different sound engines, Untz, an open source engine created specifically for Moai SDK, and FMOD, an industry standard sound library. It’s worth mentioning that FMOD costs money, while Untz is free.

We’re going to show you how to use Untz in this book, but you can safely code loadSound to use FMOD instead (take a look at MOAIFmodExSound and MOAIFmodExChannel in the Moai SDK API documentation).

function ResourceManager:loadSound ( definition )

local sound = MOAIUntzSound.new ()

local filePath = ASSETS_PATH .. definition.fileName

sound:load ( filePath )

sound:setVolume ( definition.volume )

sound:setLooping ( definition.loop )

return sound

end

This is basically the same logic as for the previous loaders, but we’re using setVolume and setLooping to use the attributes we chose on our resource definition. We’ve not initialized Untz yet; this will be done later, but this code has been explained here for the completeness of ResourceManager.

Exercises

Putting this together should be something you can achieve now. So, take the source code of the main.lua file we created previously and modify it in order to make use of our ResourceManager and ResourceDefinitions entities. You’ll need to include resource_definition.lua and resource_manager.lua in main.lua and then make good use of them. If you download the source code for this article from the website, main.lua has already been modified to work with ResourceManager.

Another exercise is to code a way to unload assets from ResourceManager. This has also been done in the code for this article, which you can download from the website.

The unload method is pretty important since it will be needed in order to actually free the memory reserved for assets.

Another interesting topic to enhance our ResourceManager entity is the use of serialized fonts so font loading is faster at runtime.

Summary

In this article we created a simple framework to work with assets. We created ways to define images, sounds, and fonts and coded the ResourceDefinitions class to store this data. We wrote our ResourceManager class, which is in charge of loading the different assets and caching them. We also went through the creation of loading functions for these different assets and explained a way to define them. Now we’re ready to start developing the gameplay for our game; how awesome is that!

Resources for Article :


Further resources on this subject:


Developing Mobile Games with Moai SDK Learn the basics of Moai SDK through developing games with this book and ebook
Published: March 2013
eBook Price: $17.99
Book Price: $29.99
See more
Select your format and quantity:

About the Author :


Francisco Tufró

Francisco Tufró has been captivated by computers and the possibility of using them to create new worlds since he was six years old. At age 14, he sort of hacked into a chat demo in Visual Basic and transformed it into a full-feature RPG chat, with support for maps, character sheets, and dice rolls. The years went by and he learned many things along the way, as any curious person does. Suddenly he found himself collaborating in various open-source projects, including Musix (a Linux distribution for musicians) and CLAM (working on the project for Google's Summer of Code 2008). He co-founded quov.is and worked as a Ruby on Rails developer for about 5 years while never forgetting about what drove him to computers in the first place, games.

He put together a team and created The Insulines, an old-school graphic adventure about rock 'n' roll and diabetes. It was thanks to this game that he first came into contact with Moai SDK. It took about 8 months of development. He fell so deeply in love with Moai SDK that now he's working full-time on it with Zipline Games.

He likes to call himself a developer, noting the difference from a programmer who is a person that has broad knowledge (not only in programming, but also in art, music, and other disciplines), perhaps not as deep as a specialized person does, but enough to tackle and solve problems in their entirety.

Books From Packt


Corona SDK application design
Corona SDK application design

Corona SDK Mobile Game Development: Beginner's Guide
Corona SDK Mobile Game Development: Beginner's Guide

Corona SDK Hotshot
Corona SDK Hotshot

Liferay Portal Systems Development
Liferay Portal Systems Development

Marmalade SDK Mobile Game Development Essentials
Marmalade SDK Mobile Game Development Essentials

Processing 2: Creative Programming Cookbook
Processing 2: Creative Programming Cookbook

PlayStation®Mobile Development Cookbook
PlayStation®Mobile Development Cookbook

Kinect for Windows SDK Programming Guide
Kinect for Windows SDK Programming Guide


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
d
F
d
L
Z
N
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software