pixelbox
Version:
A framework to fast-prototype pixel-based games
189 lines (175 loc) • 6.32 kB
JavaScript
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
/**
* @module assetLoader
* @desc Loading functions helpers
*
* @author Cedric Stoquer
*/
function loadData(path, responseType, cb) {
var xobj = new XMLHttpRequest();
xobj.responseType = responseType || 'arraybuffer';
xobj.onreadystatechange = function onXhrStateChange() {
if (~~xobj.readyState !== 4) return;
if (~~xobj.status !== 200 && ~~xobj.status !== 0) {
return cb && cb('xhrError:' + xobj.status);
}
return cb && cb(null, xobj.response);
};
xobj.open('GET', path, true);
xobj.send();
}
exports.loadData = loadData;
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
/**
* @function module:loader.loadJson
* @desc load a json file
*
* @param {String} path - file path
* @param {Function} cb - asynchronous callback function
*/
function loadJson(path, cb) {
var xobj = new XMLHttpRequest();
xobj.onreadystatechange = function () {
if (~~xobj.readyState !== 4) return;
if (~~xobj.status !== 200) return cb('xhrError:' + xobj.status);
return cb && cb(null, JSON.parse(xobj.response));
};
xobj.open('GET', path, true);
xobj.send();
}
exports.loadJson = loadJson;
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
/**
* @function module:loader.loadImage
* @desc load an image file
*
* @param {String} path - file path
* @param {Function} cb - asynchronous callback function
*/
function loadImage(path, cb) {
var img = new Image();
// TODO: remove listeners when load / error
img.onload = function () {
this.onload = null;
this.onerror = null;
cb && cb(null, this);
};
img.onerror = function () {
this.onload = null;
this.onerror = null;
cb && cb('img:' + path);
};
img.src = path;
}
exports.loadImage = loadImage;
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
/**
* @function module:loader.loadSound
* @desc load an image file
*
* @param {String} path - file path
* @param {Function} cb - asynchronous callback function
*/
function loadSound(path, cb) {
var snd = new Audio();
snd.preload = true;
snd.loop = false;
function onSoundLoad() {
cb && cb(null, snd);
snd.removeEventListener('canplaythrough', onSoundLoad);
snd.removeEventListener('error', onSoundError);
}
function onSoundError() {
cb && cb('snd:load');
snd.removeEventListener('canplaythrough', onSoundLoad);
snd.removeEventListener('error', onSoundError);
}
snd.addEventListener('canplaythrough', onSoundLoad);
snd.addEventListener('error', onSoundError);
snd.src = path;
snd.load();
}
exports.loadSound = loadSound;
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
/**
* @function module:loader.preloadStaticAssets
*
* @desc Preload all static assets of the game.
* The function first ask the server for the asset list.
* Server respond with an object containing the list of images
* to load and all data that are put in the www/asset folder.
* At this step, if request fail, function send an error.
* The function then proceed the loading of image assets.
* If an image loading fail, the loading continue, and loading
* status is set to 1 (an image load fail).
* Images are load by 5 in parallel.
*
* Function end and wil return an object that mix all data and
* all assets so that it will have the same structure as the
* 'assets' folder.
*
*
* Assets list and data are automaticaly generated by server
* Just drop images and json files in the www/asset/ folder
* and the server will take care of it !
*
*
* @param {Function} cb - asynchronous callback function to
* call when all is preloaded
*
* @param {Function} onEachLoad - optional callback function called
* every time one file is loaded
* (for loading progress purpose)
*
*/
function preloadStaticAssets(assetList, cb, onEachLoad) {
var data = assetList.dat;
var imgCount = assetList.img.length;
var count = imgCount + assetList.snd.length;
var root = assetList.root;
var load = 0;
var done = 0;
function storeAsset(path, obj) {
var splitted = path.split('/');
var filename = splitted.pop();
var id = filename.split('.');
id.pop();
id = id.join('.');
var container = data;
for (var i = 0, len = splitted.length; i < len; i++) {
container = container[splitted[i]];
}
container[id] = obj;
splitted.push(id);
obj.name = id;
obj.path = splitted.join('/');
}
function loadAssets() {
var current = load + done;
var percent = current / count;
onEachLoad && onEachLoad(load, current, count, percent);
var path;
var loadFunc;
if (current < imgCount) {
path = assetList.img[current];
loadFunc = loadImage;
} else {
path = assetList.snd[current - imgCount];
loadFunc = loadSound;
}
done += 1;
loadFunc(root + path, function onAssetLoaded(error, img) {
if (!error) storeAsset(path, img);
load += 1;
done -= 1;
if (load + done < count) loadAssets()
else if (done === 0) cb(null, data);
});
}
// loading assets in parallel, with a limit of 5 parallel downloads.
if (count === 0) return cb(null, data);
var parallel = Math.min(5, count - 1);
for (var j = 0; j <= parallel; j++) loadAssets();
// });
}
exports.preloadStaticAssets = preloadStaticAssets;