Created
April 3, 2013 09:47
-
-
Save Paratron/5299864 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Cargo Asset Loader | |
//=================== | |
//This file defines the API for a HTML5 asset loader that is mainly designed to be used for games | |
//but could be used for any kind of HTML5 application that requires some kind of asset management. | |
//@version: 1 (April 1st, 2013) | |
//@author: Christian Engel <[email protected]> | |
//The Cargo asset loader should deliver the following number of features: | |
// * Loading all needed assets (huh, obvious) | |
// * Differenciating between mandatory and optional assets | |
// * Making it easy to switch to lowRes and highRes versions of assets, depending on the environment | |
// * Providing a rich event list to enable the game to react to different situations | |
// * Providing an easy interface for accessing loaded assets | |
//The biggest difference to conventional asset loaders is, that Cargo don't just loads a number | |
//of assets and calls a callback after that has been done. Cargo should enable the developer to | |
//get the game loaded as quickly as possible by loading mandatory assets at first, maybe even with | |
//low resolution, then loading optional assets, or higher resolutions after that. | |
//A player doesn't care if the game does additional downloads in the background after it has been | |
//started, but he DOES care about having a long waiting time at the beginning. | |
//This means that developers need to approach developing their games a bit different. Asset loading | |
//with Cargo will always be asyncronous and deferred and will even continue when the user is | |
//accessing a game menu, or is already playing. | |
//When a user is in the main menu and assets for the first level are not yet fully loaded, the game | |
//needs to show a loading screen again, but the progress could already be very advanced since all | |
//the time the user has spent in the main menu has been used to pre-load the next assets. | |
//Another thing is on-the-fly updating of assets during a running game. Cargo can be configured | |
//or advised to load low-res versions of the assets to get the game running really quick. | |
//When the game is already running, optional assets or high-res assets are loaded and Cargo | |
//notifies the game logic about asset updates and additions via the included event system. | |
//------------------------------------------------------------------------------------------- | |
//At first, require a reference to the cargo asset loader via AMD or commonJS. | |
var cargo = require('cargo'); | |
//Set up the cargo object with the defaults you'd like to use. | |
//Heads up! If you require the cargo element again at a later point in your | |
//program flow, you don't need to re-configure it again. | |
cargo.config({ | |
basepathGlobal: 'lib/', //A basepath to be put in front of every relative URL. | |
basepathImage: 'img/', //Basepath for all image files. Appended to global basepath. | |
basepathSound: 'snd/', //Basepath for all sound files. Appended to global basepath. | |
basepathText: 'txt/', //Basepath for all text files. Appended to global basepath. | |
parseJSON: true, //Should the content of *.json files be parsed to objects? Default: true | |
parallels: 5, //How many parallel downloads should cargo do? | |
timeout: 2000 //After how much milliseconds with no response should an asset be considered as timed out? | |
lowResPattern: '{filename}@low.{extension}', //The default schema for low-res versions of images. | |
highResPattern: '{filename}@2x.{extension}', //The default schema for high-res versions of images. | |
cacheBusterPattern: '{filename}.{version}.{extension}', //The pattern for the cache-busting mechanism for where to apply version numbers. | |
imageTypes: ['png', 'jpg', 'gif'], //Extensions for assets to be recognized as an image. | |
soundTypes: ['mp3', 'aac', 'ogg'], //Extensions for assets to be recognized as a sound. | |
textTypes: ['txt', 'html', 'css', 'json', 'js'] //Extensions for assets to be recognized as plaintext. | |
}); | |
//About the lowRes and highRes patterns | |
//------------------------------------- | |
//Since Cargo is able to load the same asset in multiple resolutions, the package definitions | |
//have to hint Cargo that other resolutions are available. | |
//The patterns are used to help the developer to not being required to specify the URL for every | |
//version of the asset, but only saying "true" to a version. Cargo then uses the given pattern to | |
//build the URL by itself. | |
//About cache busting | |
//------------------- | |
//Dealing with the browsers cache to load | |
//The idea behind cargo is, that cargo is able to load assets in packages. | |
//For example, you define a package "ui", which you need to create your user interface from, | |
//or you need another package "level1" which contains all assets you need for your first game level. | |
//You can define one or more packages before you start loading them. | |
//Define a single package by passing in its JSON structure, or directly pass an array of package objects, | |
//or a URL to a JSON file containing the package definition(s). | |
cargo.definePackage({ | |
id: 'level1' //The identifier of this package to access it at a later point. | |
mandatory: { | |
'ship1': { //A detailed asset definition. | |
src: 'player-ship.png', //The URL to the asset. Since this is an image, it will be prefixed with basepathGlobal and basePathImage | |
fsize: 128, //Optional definition of the filesize of the asset. Used to calculate more accurate progress. | |
fsize_hi: 256, //Equivalent to fsize, but for the hiRes version. | |
fsize_lo: 64, //Equivalent to fsize, but for the loRes version. | |
hi: true, //By setting the "hi" property to true, Cargo uses the lowResPattern to guess the filename of the hiRes image. | |
lo: 'player-ship.0.5.png' //The lowRes version is specifically defined here. | |
version: 1 //Optionally specify a version number of the asset and increase it after changes to bust the browser cache. | |
}, | |
'game_bkg': 'some_background.jpg', //A shorthand asset definition. No low/high res version given. | |
'bkg_music': 'soundtrack.ogg', //Will be recognized as sound and prefixed with basepathGlobal and basepathSound. | |
'enemy_defs': 'enemies.json' //If the option parseJSON is set to true, the JSON file will be parsed automatically. | |
}, | |
optional: { | |
//Use this like the "mandatory" property. Optional assets won't be loaded until all mandatory assets are done loading. | |
} | |
}); | |
//After a package has been defined, its not instantly loaded. | |
//You may specify a great number of packages before loading anything. The idea is, that you can load one or more packages together. | |
cargo.load({ | |
packages: ['ui', 'base_assets', 'level1'], //This tells cargo which packages have to be loaded to finish the load. | |
optionals: false, //Pass false here, to completely ignore optional assets from loading. | |
incremental: true, //Pass true to automatically increase the resolution. | |
loadHighRes: false, //Setting this to "false" prevents incremental to load highRes assets. | |
progress: progressHandler, | |
finish: doStuff, | |
optionalFinish: doMoreStuff | |
error: errorHandler | |
}); | |
//Setting the incremental option to "true" will cause Cargo to download the lowRes version of all mandatory | |
//assets first, then continue with switching to standard, then continue with switching to highRes (if possible). | |
//This will cause a overall bigger traffic impact, but will get the players into the game much quicker | |
//and delivering better graphics after some time. | |
//The cargo.load() method returns a loading object which enables you to react to different events. | |
//In this example, three packages are being loaded. During the process, the progressHandler() function is | |
//being called on every update and gets passed the current loading progress. | |
function progressHandler(percent, calculatedSpeed, calculatedDuration){ | |
$('.loadingLabel').text(percent); | |
} | |
//The calculatedSpeed and calculatedDuration arguments may not contain values at the beginning. | |
//Both are calculated during the download process, when fsize hints are given in the package | |
//definitions. The speed is given in kb/s, the calculated remaining duration is given in seconds. | |
function errorHandler(fails){ | |
$.post('errortracker.php', fails); | |
} | |
//The "fails" attribute is an object that contains the keys of all assets that have been failed | |
//loading, as well as the HTTP statuscodes of the fail(s). | |
//Now lets see how we can actually work with the assets. | |
function doStuff(){ | |
var pkg, | |
ctx; | |
//We're getting a reference to the package object here for faster interaction. | |
pkg = cargo.getPackage('ui'); | |
ctx = $('#canvas')[0].getContext('2d'); | |
//Entering some kind of game loop. | |
myEngine.onFrame(function(){ | |
//This draws the asset "ship1" at the position x:1, y:1 in a canvas. | |
ctx.drawImage(pkg.get('ship1'), 1, 1); | |
}); | |
} | |
//Calling the get() method of a package will return the asset with the given key. | |
//Now its getting interesting: | |
pkg.setResoluion('high'); //high, standard, low | |
//This makes cargo download the high resolution version of every asset if neccessary. | |
//After that, the get() method automatically returns the highRes version without further | |
//configuration. | |
//Listen to the changeResolution event to get notified to resolution changes that are | |
//made manually or automatically: | |
pkg.on('changeResolution', function(res){ | |
//Maybe modify your game loop. | |
}); | |
//The res attribute can be "low", "standard" or "high" | |
//Handling optional assets | |
//------------------------ | |
//Well, the finish handler is being called after all mandatory assets have been loaded. | |
//But whats with the optional assets? | |
//You may have already spotted the "optionalFinish" option for the load() method. | |
//This callback is being called after all optional assets of a package have been loaded. | |
//When the callback has been called, you can be sure that all optional assets are available for use. | |
function doMoreStuff(){ | |
//Prepare your game for using the optional assets | |
} | |
//Optionally, you can check the "optionalsAvailable" boolean property of your package object | |
//to do a quick check inside your game loop: | |
function myGameLoop(){ | |
var pkg, | |
ctx; | |
pkg = cargo.getPackage('game_assets'); | |
ctx = $('#canvas')[0].getContext('2d'); | |
while(doLoop){ | |
ctx.drawImage(pkg.get('player'), 10, 50); | |
if(pkg.optionalsAvailable){ | |
ctx.drawImage(pkg.get('player_decoration'), 10, 50); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment