Overview


Expect this Unit to last about 2 hours. To demonstrate what you should have at the end of this Unit, check out the Demo for Unit 6.

Games need all kinds of content: images (textures), sound, data files for animation or object configuration or level data.

Many times, a single asset will be used multiple times. 10 enemies all using the same sprite. A single texture containing all the frames of a player's run animation. Typically we save memory by only have one version of the asset loaded and letting each object only have a reference to it.

This is especially important with online games. With HTML5, whenever we want an asset, we have to request it from the server. If we aren't smart about caching it, then each time we try to use an image or a data file then we will be unnecessarily requesting data from the server.


assets.js


The Asset Manager's job is to be a general purpose asset loader with the following key feataures:

We'll be adding these features directly onto the Engine's definition through the addition of just a few functions!


Loading assets - API


Let's start with the API: We want it to be super easy to load an asset without the user caring about which asset type it is. Our public facing generic loading function, called load(), should take in a list of assets to load concurrently and dispatch each one to the correct loading fuction.

API Source Code:

The three types of assets we will be concerned with at this moment are Images, Audio and Data files, so we'll write three internal loading functions: loadAssetImage(), loadAssetAudio(), loadAssetOther(). All perform the same task with a different asset type. The function parameters are:

API Source Code:


Determining what type of asset to load


So, given that the user is only going to use the load() function, we'll need to figure out what type of asset it is based on the file extension.

Let's write a handy helper functions for determining asset types based on the file extension. We can also write a function that gives us the filename with the extension removed.

These functions are assigned to the Engine namespace, and not the .prototype, meaning they act as static functions (just like GetSingleton) and not as member functions for an Engine instance.

Source Code:


Loading assets - Implementation


Since loading an asset is essentially just a request to the server to send a file to us, the process is asynchronous and we must use callbacks to be notified if and when the file loading has completed.

If you've worked in HTML to display an image or play a sound, then you're familiar with the Images and Audio objects, which will be the kinds of objects we use to both request the asset from the server and utilize it in game.

The loadAssetOther() function is what we'll use for our JSON data files. JSON is a text based data format used in games, similiar to how XML might be used, but is super lightweight and extremely convienent to utilize in JavaScript since it is syntactically identical to the code for creating JavaScript objects.

loadAssetImage()

Image assets are loaded by creating an HTML/JavaScript Image object. jQuery helps us here by assigning callbacks to two important events: 'load' if it succeeds or 'error' if it fails.

Once the Image has loaded, we call the success callback passing along the key parameter here so it can be cached.

Source Code:

loadAssetAudio()

Audio files are loaded by creating an HTML/JavaScript Audio object. Creating one would normally be just as easy as an Image object, but the truth is that audio is a super tricky issue in HTML5 games. Not all browsers necessarily support the same audio file type - some support the Ogg format, other support MP3, some other AAC.

A great way to deal with this is to have the asset loader strip off the file extension and postfix the one that is actually supported. The way we check that is by calling the Audio.canPlayType with the mime type associated with the file extension. It also means that your server should have multiple formats of the audio available to be requested by the client.

We also add an extra feature to disable loading audio if we have marked sound as disabled (muted by the player).

Source Code:

loadAssetOther()

Any other kind of asset that doesn't get loaded through a specific HTML/JavaScript object needs to be loaded through an AJAX get request, which we can easily do using jQuery's get() function. Since we are focusing on game engine development and not web development, I won't go into the HTTP GET request more than just showing you how to use it. If you plan on continuing your HTML5 game and having any online feature's such as communicating with a server, you'll likely need to a bit deeper into the topic.

NOTE: When we request JSON data from the server, we get back a JavaScript object, not the JSON string.

Source Code:

load()

Now that we've seen the implementation of our individual asset loaders, let's take a look at the general-purpose one that the user will actually use!

The basic structure of the code is to loop over asset hash and determine the asset's type to dispatch appropriate loader function. It also supports a progress callback for each item, so we can show the user something like a loading bar, and caching the assets by storing them in a hash.

Before we start loading any assets, we setup a callback for handling an error, and for tracking progress internally to this function. Each time an asset is successfully loaded, we store it in a hash array called .cachedAssets so it can be utilized later.

We cache loaded assets by an optional user-friendly key name, ie. "player_run_anims_128x128.png" could be cached unded the name "playerrun" so it's easier to reference in game code, especially since we could change the file type to a .bmp and the game could could care less. If no key is provided the system will just use the filename.

To support this we make the assetList super flexible. It can be of any of these types:

  • a string - a filename of a single asset to load (the key will be the same as the filename)
  • an object - can represent multiple assets, where each property is the asset key and the value is the filename
  • an array of strings, or of objects, or a mix of both - so the user could concatenate multiple sets of assets before passing them all over to be loaded together.

This function uses Underscore extensively, which you should be comfortable enough with by now to look up and understand it's usage here.

Source Code:


Requesting cached assets - API and Implementation


Well, this one is so straight forward I won't even bother separating the API from the implementation.

We already know how we're storing our cached assets, so for retrieving them we need only to write a function that does some safety checking first.

getAsset()

Source Code:


Test code


Look at this test code and make sure you understand what's going on.

Question: If you remember we don't load assets that we already have cached, and the system just pretends it succeeds as normal. But assets are cached by the key, so technically you could have the same asset file cached multiple times under different key names. Can you tell how many times "title_music.mp3" gets loaded here?

Source Code:


Homework


Part 1. Create and add the assets.js file to your project in the /js_engine sub-directory.

Part 2. Fill out assets.js with the code from this Unit.

Part 3. Create a new subdirectory to store game assets in, such as /gamedata. Put a few sample assets in there (an image file, an audio file, a JSON file)

Part 4. Load an Image asset. If you are comfortable with manipulating the DOM directly or through jQuery, try displaying that image in the HTML page after it's finished loading.

Part 5. Load an Audio asset. Once it's loaded play it

Part 6. Load a JSON data file (If testing locally, this is where you'll need to be using a web hosting application like Mongoose)

Part 7. Try loading a batch of assets, and update a loading bar (one idea is that you could use HTML and CSS to display and update a loading bar).