Last active
December 23, 2015 23:39
-
-
Save 6174/6711116 to your computer and use it in GitHub Desktop.
resource manager
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
/** | |
* @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' | |
] | |
}); |
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
/** | |
* @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; | |
}); |
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
/** | |
* @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