/**
* @module cloudkid
*/
(function() {
"use strict";
/**
* AssetManager is responsible for managing different resolutions of assets and spritesheets
* based on the resolution of the stage. This is a helpful optimization for PIXI because some low-hardware
* devices have a problem keeping up with larger images, or just refuse large images entirely.
* The AssetManager does not load assets itself, or keep track of what is loaded. It merely assists in
* loading the appropriate assets, as well as easily unloading assets when you are done using them.
*
* @class AssetManager
*/
var AssetManager = {};
/**
* Dictionary of scales by asset id. Use this to return your asset to normal size.
* Assets are only added to this dictionary after a url has been retrieved with getUrl().
* @property {Object} scales
* @final
* @static
*/
AssetManager.scales = null;
/**
* The available size definitions, e.g., {"maxSize":400, "order": ["tiny", "sd"]}
* @property {Array} sizes
* @private
* @static
*/
var sizes = null;
/**
* Dictionary of assets by asset id
* @property {Object} assets
* @private
* @static
*/
var assets = null;
/**
* The cache of asset url paths
* @property {Object} assetUrlCache
* @private
* @static
*/
var assetUrlCache = null;
/**
* The scaling value for each asset size id, e.g., {"sd" : 1, "tiny" : 2}
* @property {Object} scales
* @private
* @static
*/
var scales = null;
/**
* The paths to each resolution folder, e.g., {"sd":"images/sd/", "tiny":"images/tiny/"}
* @property {Object} paths
* @private
* @static
*/
var paths = null;
/**
* The collection of perferred size to load
* @property {Array} sizeOrder
* @private
* @static
*/
var sizeOrder = null;
/**
* If we should use low hardware, if we know we're on a slow device
* @property {Boolean} lowHW
* @static
*/
AssetManager.lowHW = false;
/**
* Initialize the asset manager. The asset manager is capable of taking different paths for
* each size of image as well as an animation file path for Spine animations. Image assets do not
* have to exist in each size. Fonts are marked for unloading purposes. Example config file:
*
{
"path": {
"sd": "images/sd/",
"tiny": "images/tiny/",
"anim": "anims/"
},
"scale": {
"sd": 1,
"tiny": 2
},
"sizing": [
{
"maxSize": 400,
"order": [
"tiny",
"sd"
]
},
{
"maxSize": 10000,
"order": [
"sd",
"tiny"
]
}
],
"assets": {
"transition": {
"src": "transition.json",
"anim": true
},
"TransitionSheet": {
"src": "ui/TransitionSheet.json",
"sd":true,
"tiny":true
},
"FoodTruck_Title": {
"src": "backgrounds/FoodTruck_Title.jpg",
"sd":true,
"tiny":true
},
"StartButton": {
"src": "ui/StartButton.png",
"sd":true,
"tiny":false
},
"LevelTitleFont": {
"src": "ui/LevelTitleFont.xml",
"sd": true,
"tiny": false,
"isFont": true
}
}
*
* @method init
* @static
* @param {Object} config The configuration file which contains keys for "path", "scale", "sizing", "assets"
* @param {Number} width The stage width
* @param {Number} height The stage height
*/
AssetManager.init = function(config, width, height)
{
AssetManager.scales = {};
assets = config.assets;
assetUrlCache = {};
paths = config.path;
sizes = config.sizing;
scales = config.scale;
pickScale(width, height);
};
/**
* Get the alias of the preferred size to use
* @method getPreferredSize
* @static
* @return {String} The alias for the preferred size
*/
AssetManager.getPreferredSize = function()
{
return sizeOrder[0];
};
/**
* Get the preferred scale amount
* @method getPreferredScale
* @static
* @return {Number} The scale amount associated with the preferred size
*/
AssetManager.getPreferredScale = function()
{
return scales[sizeOrder[0]];
};
/**
* Pick the preferred scale based on the screen resolution
* @method pickScale
* @private
* @static
* @param {Number} width The stage width
* @param {Number} height The stage height
*/
var pickScale = function(width, height)
{
var minSize = width < height ? width : height;
var s;
for(var i = sizes.length - 1; i >= 0; --i)
{
if(sizes[i].maxSize > minSize)
s = sizes[i];
else
break;
}
sizeOrder = s.order;
};
/**
* Get a asset url by asset id
* @method getUrl
* @static
* @param {String} assetId The unique asset id
* @return The url of the asset at the appropriate size.
*/
AssetManager.getUrl = function(assetId)
{
var a = assets[assetId];
if(!a) return null;
if(assetUrlCache[assetId])
return assetUrlCache[assetId];
var url;
if(a.anim)
{
url = assetUrlCache[assetId] = paths.anim + a.src;
return url;
}
if(AssetManager.lowHW && a.lowHW)
{
AssetManager.scales[assetId] = scales[a.lowHW];
url = assetUrlCache[assetId] = paths[a.lowHW] + a.src;
return url;
}
for(var i = 0; i < sizeOrder.length; ++i)
{
var typeId = sizeOrder[i];
if(a[typeId])
{
AssetManager.scales[assetId] = scales[typeId];
url = assetUrlCache[assetId] = paths[typeId] + a.src;
return url;
}
}
return null;
};
/**
* Unload an asset or list of assets.
* @method unload
* @static
* @param {Array|String} assetOrAsset The collection of asset ids or single asset id
*/
AssetManager.unload = function(assetOrAssets)
{
if(assetOrAssets instanceof Array)
{
for(var i = assetOrAssets.length - 1; i >= 0; --i)
{
var id = assetOrAssets[i];
unloadAsset(id);
}
}
else//string
{
unloadAsset(assetOrAssets);
}
};
/**
* Unload an asset
* @method unloadAsset
* @static
* @private
* @param {String} asset The asset id to unload
*/
var unloadAsset = function(asset)
{
if(!assetUrlCache[asset]) return;//if this doesn't exist, then it wasn't loaded
var a = assets[asset];
if(!a) return;//asset never existed in the master list
if(a.anim) return;//don't unload these, they are pretty small
if(a.isFont)
{
if(PIXI.BitmapText.fonts[asset])
delete PIXI.BitmapText.fonts[asset];
}
//anything else is a texture
PIXI.Texture.destroyTexture(assetUrlCache[asset]);
delete AssetManager.scales[asset];
delete assetUrlCache[asset];
};
/**
* Assemble a dictionary of Texture arrays representing animations from the PixiJS texture cache.
* Example of a getAnims() call:
var animationDictionary = AssetManager.getAnims(
{
"bobIdleHappy":{"name":"bob_idle_happy#", "numberMin":1, "numberMax":139},
"bobIdleNeutral":{"name":"bob_idle_neutral#", "numberMin":1, "numberMax":140},
"bobIdleMad":{"name":"bob_idle_mad#", "numberMin":1, "numberMax":140},
"bobPos":{"name":"bob_react_pos#", "numberMin":1, "numberMax":23},
"bobNeg":{"name":"bob_react_neg#", "numberMin":1, "numberMax":31},
},
4);
* @method getAnims
* @static
* @param {Object} anims The dictionary of animation assets
* @param {int} [maxDigits=4] Maximum number of digits, like 4 for an animation exported as anim_0001.png
* @param {Object} [outObj] If already using an return object
* @return {Object} An collection of PIXI.Textures for each animation id suitable for use in PIXI.MovieClip
*/
AssetManager.getAnims = function(anims, maxDigits, outObj)
{
if(maxDigits === undefined)
maxDigits = 4;
if(maxDigits < 0)
maxDigits = 0;
var zeros = [];
var compares = [];
var i, c;
for(i = 1; i < maxDigits; ++i)
{
var s = "";
c = 1;
for(var j = 0; j < i; ++j)
{
s += "0";
c *= 10;
}
zeros.unshift(s);
compares.push(c);
}
var compareLength = compares.length;
var rtnDict = outObj || {};
var fromFrame = PIXI.Texture.fromFrame;
var prevTex, len;
for(var a in anims)
{
var data = anims[a];
var list = [];
for(i = data.numberMin, len = data.numberMax; i <= len; ++i)
{
var num = null;
for(c = 0; c < compareLength; ++c)
{
if(i < compares[c])
{
num = zeros[c] + i;
break;
}
}
if(!num)
num = i.toString();
//If the texture doesn't exist, use the previous texture - this should allow us to use fewer textures
//that are in fact the same
var texName = data.name.replace("#", num);
var tex = fromFrame(texName, true);
if(tex)
prevTex = tex;
list.push(prevTex);
}
rtnDict[a] = list;
}
return rtnDict;
};
// Assign to the namespace
namespace('cloudkid').AssetManager = AssetManager;
namespace('cloudkid.pixi').AssetManager = AssetManager;
}());