Skip to content

Instantly share code, notes, and snippets.

@6174
Last active December 23, 2015 23:39
Show Gist options
  • Save 6174/6711116 to your computer and use it in GitHub Desktop.
Save 6174/6711116 to your computer and use it in GitHub Desktop.
resource manager
/**
* @object: ResourceManager
* @desc: 资源管理器, 控制游戏的资源加载
* 实现细化的加载策略, 队列加载, 提前优先加载
* 在一个资源包中可以管理并行加载的资源, 可以通过监听progress事件以及ev.loadedArr处理
* 资源包是按照阻塞式加载方式进行
*
* @author: [email protected]
* @date: 2013-09-14
*
*/
;
KISSY.add('khc/lib/resourceManager', function(S, Event, Resource) {
/**
* 整个游戏的资源配置sample
* priority 越大, 越后加载
*/
var RESOURCES = {
//--游戏背景图片
'game-background': {
name: 'game-background',
priority: 1,
res: [{
name: 'map1',
src: '../img/map1.png'
}, {
name: 'map2',
src: '../img/map2.png'
}]
},
//-- 游戏当中的小人
'sprite-hero': {
name: 'sprite-hero',
priority: 2,
res: [{
name: 'sprite1',
src: '../img/sprite1.png'
}]
},
//-- 游戏当中的飞艇
'fly-boat': {
name: 'fly-boat',
priority: 3,
res: [{
name: 'boat1',
src: '../img/boat1.png'
}]
}
};
/**
* @object ResouceManager
* 资源加载的过程:
* _unloadRes -> _loadQueue -> _loadingRes -> _loadedRes or _errorRes
*
*/
var ResourceManager = {
//--未加载的资源, 新添加的资源将放入这里边
_unloadRes: {},
//--加载的资源队列
_loadQueue: {},
//--正在加载的资源
_loadingRes: null,
//--已经加载完了的资源
_loadedRes: {},
//--error 资源
_errorRes: {},
_loadingStopped: true
};
/**
* 加载成功一个资源会触发(load + 资源名)的事件
* 加载失败一个资源会触发(error + 资源名)的事件
*/
S.mix(ResourceManager, S.EventTarget);
S.mix(ResourceManager, {
/**
* @method init
* @desc: 初始化要加载的资源列表
*/
init: function(resources) {
var self = this;
//--只能初始化一次
if (self._inited) {
return true;
}
self._unloadRes = resources;
//-- 根据列表中的优先级排序
//-- 排序结果加入到unloading的队列当中
self._loadQueue = self._sort(resources);
self._load();
},
/**
* @method _sort
* @desc: 根据列表的优先级别排序
* @param: {object}--resources
* @note: 为了减少外部依赖, 方便测试, 就算是内部属性也通过参数方式传递
*/
_sort: function(res) {
var self = this;
var tempArr = [];
var item;
//-- 将res变为数组方式
for (it in res) {
if (res.hasOwnProperty(it)) {
item = res[it];
tempArr.push(item);
}
}
//-- 按照优先级关系, 从小到大排序
tempArr.sort(function(a, b) {
return a.priority - b.priority;
});
return tempArr;
},
/**
* @method _loadAResource
* @desc 内部加载方法, 加载一个资源对象
* @param {object}--resDef
*/
_loadAResource: function(resDef, successBack, errorBack) {
var self = this;
var resObj;
//--判断是否是在loading或者loaded中, 如果是, 返回
if (!resDef || self._loadedRes[resDef.name] || self._loadedRes[resDef.name]) {
return;
}
if (resDef.resObj) {
// console.log('load by stopped resObj');
resDef.resObj.load();
return;
}
//-- 生成资源对象
resObj = new Resource(resDef.res);
//-- 将资源对象的resDef放到_loadingRes中
resDef.resObj = resObj;
self._loadingRes = resDef;
//-- 资源未加载成功
resObj.on('error', function(ev) {
self.fire('error-' + resDef.name, {
resDef: resDef
});
self._loadingRes = null;
errorBack.call(self);
});
//--资源加载过程
resObj.on('progress', function(ev) {
self.fire('progress-' + resDef.name, {
percent: ev.percent,
res: ev.res
});
});
//--stoped
resObj.on('stop', function() {
// self._load();
});
//-- 资源被加载成功
resObj.on('load', function(ev) {
self.fire('load-' + resDef.name, {
resDef: resDef,
res: ev.res
});
self._loadingRes = null;
successBack.call(self);
}).load();
},
/**
* @method _load
* 加载资源队列
*/
_load: function() {
var self = this;
var len = self._loadQueue.length;
if (len <= 0) {
self._loadingStopped = true;
return;
}
self._loadingStopped = false;
//-- 每次从loadQueue中取出第一个资源
var resDef = self._loadQueue.shift();
//-- 将这个资源从unloadRes中删除
delete self._unloadRes[resDef.name];
var successBack = function() {
self._loadedRes[resDef.name] = resDef;
//--继续加载其他资源
self._load();
};
var errorBack = function() {
self._errorRes[resDef.name] = resDef;
//--继续加载其他资源
self._load();
};
self._loadAResource(resDef, successBack, errorBack);
},
/**
* @method: load
* @desc; 对外的load方法
* @param {Object/Array/String}
* 当参数为Array的时候
*/
load: function(resources, needChangePriority) {
var self = this;
var resDef;
//--resources不能为空
if (!resources) {
return;
}
if (S.isArray(resources) || S.isString(resources)) {
loadResNameArr();
return;
};
loadResGroup();
//--如果参数是数组, 将数组里边的名称优先级提高
function loadResNameArr() {
var resNameArr = resources;
var name;
var needReload = false;
if (self._loadingRes) {
needReload = true;
//-- stop loading
self._loadingRes.resObj.stopLoad();
name = self._loadingRes.name;
self._loadingRes.priority = 1;
//-- add to the _unloadRes
self._unloadRes[self._loadingRes.name] = self._loadingRes;
}
S.each(self._unloadRes, function(item) {
item.priority += 1;
});
//--字符串
if (S.isString(resources)) {
if (self._unloadRes[resources]) {
self._unloadRes[resources].priority = 0;
}
} else {
//--数组
S.each(resNameArr, function(item, index) {
if (self._unloadRes[item]) {
self._unloadRes[item].priority = 0;
}
});
}
//--重新排序
self._loadQueue = self._sort(self._unloadRes);
//--判断是否还在下载, 如果没有, 那么重新调用_load函数
if (self._loadingStopped || needReload) {
self._load();
}
}
//--如果参数是对象, 那么表示是要加载新的资源
function loadResGroup() {
var maxPriority = 0;
var needReload = false;
//--将resource放到_unloadRes
for (it in resources) {
if (resources.hasOwnProperty(it)) {
if (!self._unloadRes[it]) {
resDef = resources[it];
self._unloadRes[it] = resDef;
maxPriority = resDef.priority > maxPriority ? resDef.priority : maxPriority;
}
}
}
if (self._loadingRes) {
needReload = true;
//-- stop loading
self._loadingRes.resObj.stopLoad();
name = self._loadingRes.name;
if (needChangePriority) {
self._loadingRes.priority = maxPriority;
}
//-- add to the _unloadRes
self._unloadRes[self._loadingRes.name] = self._loadingRes;
}
if (needChangePriority) {
S.each(self._unloadRes, function(item) {
item.priority += maxPriority + 1;
});
}
//--重新排序
self._loadQueue = self._sort(self._unloadRes);
//--判断是否还在下载, 如果没有, 那么重新调用_load函数
if (self._loadingStopped || needReload) {
self._load();
return;
}
}
},
/**
* @method: get
* @desc: 获取资源
*/
get: function(resName) {
var self = this;
if (!S.isString(resName)) {
return false;
}
//--如果在下载错误中找到,那么证明下载错误
if (self._errorRes[resName]) {
return {
readyState: '3',
data: self._loadingRes
}
}
//--如果在downloading中找到, 那么证明还在下载
if (self._loadingRes[resName]) {
return {
readyState: '1',
data: self._loadingRes
}
}
//--从下载到的资源当中获取
if (self._loadedRes[resName]) {
return {
readyState: '2',
data: self._loadedRes[resName]
}
}
//--如果在_unloadRes中找到, 那么证明还没有开始下载
if (self._unloadRes[resName]) {
return {
readyState: '0',
data: self._unloadRes[resName]
}
}
return false;
}
});
return ResourceManager;
}, {
requires: [
'event',
'khc/lib/resource'
]
});
/**
* @object -- game resource
*/
KISSY.add('khc/mods/game/carnival/gameResource', function(S) {
var BASE_PATH = '../src/image/game/carnival/';
var X_SIZE = 10;
var Y_SIZE = 10;
var carnivalCfg = [{
name: 'map',
src: P('map.jpg')
}, {
name: 'train',
src: P('train.png')
}, {
name: 'bubble',
src: P('bubble.png')
}, {
name: 'error',
src: P('error.png')
}];
//---map 10 X 10 = 12k X 100
var mapPakInitial = createMapPakCfg(getMapPakArr(1, 3));
var mapPakAll = createMapPakCfg(getMapPakArr(0, 9));
var mapPak1 = createMapPakCfg([1, 2, 3]);
var mapPak2 = createMapPakCfg([4, 5, 6]);
var RESOURCE = {
'carnival': {
name: 'carnival',
priority: 1,
res: carnivalCfg
},
'mapPak1': {
name: 'mapPak1',
priority: 2,
res: mapPak1
},
'mapPak2': {
name: 'mapPak2',
priority: 3,
res: mapPak2
},
'mapPakAll': {
name: 'mapPakAll',
priority: 4,
res: mapPakAll
}
};
/**
* @method getMapPakArr
* @param {Number} -- a, b
* @return {Array} -- one dim
*/
function getMapPakArr(a, b) {
var arr = [];
var i, j, n;
a = a < 0 ? 0 : a;
b = b < 0 ? 0 : b;
a = a > X_SIZE ? X_SIZE : a;
b = b > Y_SIZE ? Y_SIZE : b;
for(i = a; i <= b; i++){
for(j = a; j <= b; j++){
arr.push(j * X_SIZE + i + 1);
}
}
return arr;
}
/**
* return map pak according to arr
*/
function createMapPakCfg(arr) {
var ret = [];
S.each(arr, function(item, index) {
var res = {};
var name = 'map_';
if (item < 10) {
name += '0';
}
name += item.toString();
res = {
name: name,
src: P('map/' + name + '.jpg')
};
ret.push(res);
});
return ret;
}
/**
* @method p
* @param {String} -- image name
* @return {String} -- full path
*/
function P(imageName) {
return BASE_PATH + imageName;
}
return RESOURCE;
});
/**
* @author [email protected]
*/
KISSY.add("khc/lib/resource", function(S) {
/**
* @class Resource
*
*/
function Resource(resCfg) {
var self = this;
S.mix(self, {
res: resCfg,
_unloadRes: resCfg,
_loadingRes: {},
_loadedRes: {},
_errorRes: {},
loaded: false,
loadedCount: 0,
errorCount: 0,
size: resCfg.length
});
}
//--cache img
S.mix(Resource, {
sources: {}
});
S.augment(Resource, S.EventTarget, {
/**
* @method load
*/
load: function() {
var self = this;
var unloadRes = self._unloadRes;
self._stopped = false;
S.each(unloadRes, function(item, index) {
var img;
var sources = Resource.sources;
if (!item.src) {
throw new Error('no src attr');
return;
}
//--if in source pool
if(Resource.sources[item.src]){
// S.log('========from cache');
item.img = Resource.sources[item.src].img;
self._loadedRes[item.name] = item;
fireEv;
}
img = new Image;
img.onload = onloadHandler;
img.onerror = onerrorHandler;
function onloadHandler() {
// S.log('========loaded-' + item.name);
Resource.sources[item.src] = {
img: img,
name: item.name,
type: 'success'
};
self._loadedRes[item.name] = item;
self.loadedCount++;
fireEv();
};
function onerrorHandler() {
Resource.sources[item.src] = {
img: img,
name: item.name,
type: 'failed'
};
self._errorRes[item.name] = item;
if(!self._stopped){
// S.log('========error-' + item.name);
self.errorCount++;
}
fireEv();
};
function fireEv(){
delete self._loadingRes[item.name];
self.fire('progress', {
percent: self.loadedCount / self.size,
loadedCount: self.loadedCount,
errorCount: self.errorCount,
type: 'success',
res: item
});
if (!self._stopped && !self.loaded && (self.errorCount + self.loadedCount) === self.size) {
self.loaded = true;
self.fire('load', {
res: self._loadedRes,
errorRes: self._errorRes
});
}
}
item.img = img;
self._loadingRes[item.name] = item;
img.src = item.src;
});
self._unloadRes = [];
},
/**
* @method unload
*
*/
stopLoad: function() {
var self = this;
self._stopped = true;
S.each(self._loadingRes, function(item, index){
// S.log('========cancel-' + item.name);
item.img.src = '';
self._unloadRes.push(item);
});
self.fire('stop');
return self;
}
});
return Resource;
}, {
requires: [
'event'
]
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment