diff --git a/.gitignore b/.gitignore index f5e28b036a..73b9c1ae31 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ node_modules /tools/jsdoc_toolkit-2.4.0 /package /tools/jsdoc_toolkit/jsdoc_toolkit-2.4.0 +/.project diff --git a/AUTHORS.txt b/AUTHORS.txt index 208e7edf3e..5a20dc7535 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -1,22 +1,20 @@ Cocos2d-html5 authors -(ordered by the join in time) +(Ordered by join time) Core Developers: Shun Lin (Sean Lin) - Hao Wu (WuHao) - - Dingping Lv (David Lv) - Ricardo Quesada - Huabin LING (pandamicro) + Huabin LING (@pandamicro) + + Sijie Wang (@VisualSJ) - Sijie Wang + Long Jiang (@jianglong0156) - Jialong Zhai + Menghe Zhang (@ZhangMenghe) Contributors: Name GithubID Main contribution @@ -86,8 +84,9 @@ Kang-Hao Lu(Opera/Oupeng) @kennyluck Optimize John Resig's inheritance patter Mark Henderson @MarkEHenderson Code review, LabelTTF and Scale9Sprite bug fix Jing Wang @06wj CCScheduler improvements - Js file loading image add - cc.RectApplyAffineTransform improvements + Js file loading image add + cc.RectApplyAffineTransform improvements + Fixed a bug of cc.Node.setPosition that parameter check is incorrect Ze Wang @WanderWang Fix crash when BrowserTypes match nothing from navigator.userAgent LabelTTF improvements @@ -164,17 +163,22 @@ erykwalder @erykwalder Function.prototype.bind bug fix ZippoLag @ZippoLag cc.Application.getCurrentLanguage bug fix typo fix + Fixed `cc.TMXObjectGroup#objectNamed` not returning the result bug Asano @LaercioAsano cc.Node bug fix Bruno Assarisse @bassarisse cc.LabelBMFont bug fix -musikov @musikov cc.ClippingNode bug fix +Mykyta Usikov @musikov cc.ClippingNode bugs fix cc.fontLoader bug fix Inverted ClippingNode with DrawNode as stencil bug fix under canvas render mode JumpTo bug with wrong _delta position bug fix - cc.ProgressTimer bug fix - cc.Scale9Sprite bug fix + cc.ProgressTimer bugs fix + cc.Scale9Sprite bugs fix + cc.RenderTexture bug fix + cc.ParticleSystem bug fix + Made CCProgressTimerCanvasRenderCmd to properly show colorized sprites + cc.ScrollView and cc.TableView: added check for parent visibility in onTouchBegan method Han XiaoLong @kpkhxlgy0 cc.ParticleSytem bug fix @@ -185,6 +189,8 @@ Xiaodong Liu @tianxing113 cc.Spawn.create bug fix Park Hyun Chen @sincntx Touch anywhere of screen to finish input when using cc.EditBox ccui.TextBMFont bug fix + cc.game bug fix + Fixed an issue of cc.ArmatureAnimation's setMovementEventCallFunc Ninja Lau @mutoo A typo bug in UILayout fix One-loop CCArmatureAnimation can't finish when setSpeedScale is less than 1.0 bug fix @@ -216,9 +222,64 @@ nopakos @nopakos cc.Texture2D bug fix Robert Rouhani @Robmaister cc.TMXMapInfo bug fix cc.TMXLayer bug fix +Igor Mats @IgorMats cc.Scale9Sprite bug fix + Spine runtime update + Add getStroke and setStroke method to cc.MotionStreak + +Tim @duhaibo0404 ccs.csLoader bug fix + +Hermanto @man2 cc.loader bug fix + +Long Jiang @jianglong0156 cc.LabelBMFont bug fix + KeyCode bug fix + ccui.ListView bug fix + +Joe Lafiosca @lafiosca Added Javascript file loader + +galapagosit @galapagosit ccs.actionManager bug fix + +Dany Ellement @DEllement cc.FontDefinition & ccui.RichText improvements + cc.LayerGradient improvements + +IShm @IShm cc.Screen bug fix + cc.ParticleSystem bug fix + ccui.PageView bug fix + Fixed crash when character not found into BMP font + Fixed restoring of sprite's color issue + +Thomas Jablonski @thomas-jablonski cc.audioEngine bug fix + Cocostudio typo fix + +WingGao @WingGao cc.TMXLayer bug fix + +Skliar Ihor @igogo5yo Add Bower support + +feijing566 @feijing566 cc.Audio bug fix + +RackovychV @RackovychV Fixed a bug of `cc.Scheduler`'s `pauseAllTargetsWithMinPriority` + +giuseppelt @giuseppelt Fixed TransitionSlideX callback sequence issue + +YShumov @pixmaster Fixed issue in music end event + +SPACELAN @spacelan Fixed `inverse` function bug of `cc.math.Matrix4` + +patriciog @patriciog Allowed timeline animations with only one frame + +Ningxin Hu @huningxin SIMD.js optimization for kazmath functions + +Zachary Lester @ZLester Fix typo in AUTHORS.txt + +Juan Carlos @Ruluk Fixed a bug where not resetting cc.Audio._ignoreEnded when replaying a sound caused it to stay in a "playing" state + +Maxim Litvinov @metalim Throw new Error object instead of error message string + Retired Core Developers: Shengxiang Chen (Nero Chan) Xingsen Ma + Jialong Zhai (@JoshuaAstray) + Hao Wu (WuHao) + Dingping Lv (David Lv) Cocos2d-x and cocos2d-html5 can not grow so fast without the active community. diff --git a/CCBoot.js b/CCBoot.js index ad2fe3c4c2..22c50494b6 100644 --- a/CCBoot.js +++ b/CCBoot.js @@ -1,6 +1,6 @@ /**************************************************************************** Copyright (c) 2011-2012 cocos2d-x.org - Copyright (c) 2013-2014 Chukong Technologies Inc. + Copyright (c) 2013-2015 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -32,9 +32,7 @@ var cc = cc || {}; cc._tmp = cc._tmp || {}; cc._LogInfos = {}; -/** @expose */ -window._p; -_p = window; +var _p = window; /** @expose */ _p.gl; /** @expose */ @@ -45,8 +43,10 @@ _p.DeviceOrientationEvent; _p.DeviceMotionEvent; /** @expose */ _p.AudioContext; -/** @expose */ -_p.webkitAudioContext; +if (!_p.AudioContext) { + /** @expose */ + _p.webkitAudioContext; +} /** @expose */ _p.mozAudioContext; _p = Object.prototype; @@ -54,18 +54,35 @@ _p = Object.prototype; _p._super; /** @expose */ _p.ctor; -delete window._p; +_p = null; -cc.newElement = function (x) { - return document.createElement(x); -}; +/** + * drawing primitive of game engine + * @type {cc.DrawingPrimitive} + */ +cc._drawingUtil = null; -cc._addEventListener = function (element, type, listener, useCapture) { - element.addEventListener(type, listener, useCapture); -}; +/** + * main Canvas 2D/3D Context of game engine + * @type {CanvasRenderingContext2D|WebGLRenderingContext} + */ +cc._renderContext = null; +cc._supportRender = false; + +/** + * Main canvas of game engine + * @type {HTMLCanvasElement} + */ +cc._canvas = null; + +/** + * The element contains the game canvas + * @type {HTMLDivElement} + */ +cc.container = null; +cc._gameDiv = null; -//is nodejs ? Used to support node-webkit. -cc._isNodeJs = typeof require !== 'undefined' && require("fs"); +window.ENABLE_IMAEG_POOL = true; /** * Iterate over an object or an array, executing a function for each matched element. @@ -95,11 +112,11 @@ cc.each = function (obj, iterator, context) { * @param {object} *sources * @returns {object} */ -cc.extend = function(target) { +cc.extend = function (target) { var sources = arguments.length >= 2 ? Array.prototype.slice.call(arguments, 1) : []; - cc.each(sources, function(src) { - for(var key in src) { + cc.each(sources, function (src) { + for (var key in src) { if (src.hasOwnProperty(key)) { target[key] = src[key]; } @@ -108,13 +125,33 @@ cc.extend = function(target) { return target; }; +/** + * Another way to subclass: Using Google Closure. + * The following code was copied + pasted from goog.base / goog.inherits + * @function + * @param {Function} childCtor + * @param {Function} parentCtor + */ +cc.inherits = function (childCtor, parentCtor) { + function tempCtor() {} + tempCtor.prototype = parentCtor.prototype; + childCtor.superClass_ = parentCtor.prototype; + childCtor.prototype = new tempCtor(); + childCtor.prototype.constructor = childCtor; + + // Copy "static" method, but doesn't generate subclasses. + // for( var i in parentCtor ) { + // childCtor[ i ] = parentCtor[ i ]; + // } +}; + /** * Check the obj whether is function or not * @param {*} obj * @returns {boolean} */ -cc.isFunction = function(obj) { - return typeof obj == 'function'; +cc.isFunction = function (obj) { + return typeof obj === 'function'; }; /** @@ -122,8 +159,8 @@ cc.isFunction = function(obj) { * @param {*} obj * @returns {boolean} */ -cc.isNumber = function(obj) { - return typeof obj == 'number' || Object.prototype.toString.call(obj) == '[object Number]'; +cc.isNumber = function (obj) { + return typeof obj === 'number' || Object.prototype.toString.call(obj) === '[object Number]'; }; /** @@ -131,8 +168,8 @@ cc.isNumber = function(obj) { * @param {*} obj * @returns {boolean} */ -cc.isString = function(obj) { - return typeof obj == 'string' || Object.prototype.toString.call(obj) == '[object String]'; +cc.isString = function (obj) { + return typeof obj === 'string' || Object.prototype.toString.call(obj) === '[object String]'; }; /** @@ -140,8 +177,9 @@ cc.isString = function(obj) { * @param {*} obj * @returns {boolean} */ -cc.isArray = function(obj) { - return Object.prototype.toString.call(obj) == '[object Array]'; +cc.isArray = function (obj) { + return Array.isArray(obj) || + (typeof obj === 'object' && Object.prototype.toString.call(obj) === '[object Array]'); }; /** @@ -149,8 +187,8 @@ cc.isArray = function(obj) { * @param {*} obj * @returns {boolean} */ -cc.isUndefined = function(obj) { - return typeof obj == 'undefined'; +cc.isUndefined = function (obj) { + return typeof obj === 'undefined'; }; /** @@ -158,10 +196,8 @@ cc.isUndefined = function(obj) { * @param {*} obj * @returns {boolean} */ -cc.isObject = function(obj) { - var type = typeof obj; - - return type == 'function' || (obj && type == 'object'); +cc.isObject = function (obj) { + return typeof obj === "object" && Object.prototype.toString.call(obj) === '[object Object]'; }; /** @@ -175,12 +211,12 @@ cc.isCrossOrigin = function (url) { return false; } var startIndex = url.indexOf("://"); - if (startIndex == -1) + if (startIndex === -1) return false; var endIndex = url.indexOf("/", startIndex + 3); - var urlOrigin = (endIndex == -1) ? url : url.substring(0, endIndex); - return urlOrigin != location.origin; + var urlOrigin = (endIndex === -1) ? url : url.substring(0, endIndex); + return urlOrigin !== location.origin; }; //+++++++++++++++++++++++++something about async begin+++++++++++++++++++++++++++++++ @@ -193,8 +229,9 @@ cc.isCrossOrigin = function (url) { * @param {object} target * @constructor */ -cc.AsyncPool = function(srcObj, limit, iterator, onEnd, target){ +cc.AsyncPool = function (srcObj, limit, iterator, onEnd, target) { var self = this; + self._finished = false; self._srcObj = srcObj; self._limit = limit; self._pool = []; @@ -203,10 +240,10 @@ cc.AsyncPool = function(srcObj, limit, iterator, onEnd, target){ self._onEnd = onEnd; self._onEndTarget = target; self._results = srcObj instanceof Array ? [] : {}; - self._isErr = false; + self._errors = srcObj instanceof Array ? [] : {}; - cc.each(srcObj, function(value, index){ - self._pool.push({index : index, value : value}); + cc.each(srcObj, function (value, index) { + self._pool.push({index: index, value: value}); }); self.size = self._pool.length; @@ -215,59 +252,70 @@ cc.AsyncPool = function(srcObj, limit, iterator, onEnd, target){ self._limit = self._limit || self.size; - self.onIterator = function(iterator, target){ + self.onIterator = function (iterator, target) { self._iterator = iterator; self._iteratorTarget = target; }; - self.onEnd = function(endCb, endCbTarget){ + self.onEnd = function (endCb, endCbTarget) { self._onEnd = endCb; self._onEndTarget = endCbTarget; }; - self._handleItem = function(){ + self._handleItem = function () { var self = this; - if(self._pool.length == 0) - return; //return directly if the array's length = 0 - if(self._workingSize >= self._limit) - return; //return directly if the working size great equal limit number + if (self._pool.length === 0 || self._workingSize >= self._limit) + return; //return directly if the array's length = 0 or the working size great equal limit number + var item = self._pool.shift(); var value = item.value, index = item.index; self._workingSize++; - self._iterator.call(self._iteratorTarget, value, index, function(err){ - if(self._isErr) - return; + self._iterator.call(self._iteratorTarget, value, index, + function (err, result) { + if (self._finished) { + return; + } - self.finishedSize++; - self._workingSize--; - if(err) { - self._isErr = true; - if(self._onEnd) - self._onEnd.call(self._onEndTarget, err); - return; - } + if (err) { + self._errors[this.index] = err; + } + else { + self._results[this.index] = result; + } - var arr = Array.prototype.slice.call(arguments, 1); - self._results[this.index] = arr[0]; - if(self.finishedSize == self.size) { - if(self._onEnd) - self._onEnd.call(self._onEndTarget, null, self._results); - return; - } - self._handleItem(); - }.bind(item), self); + self.finishedSize++; + self._workingSize--; + if (self.finishedSize === self.size) { + var errors = self._errors.length === 0 ? null : self._errors; + self.onEnd(errors, self._results); + return; + } + self._handleItem(); + }.bind(item), + self); }; - self.flow = function(){ + self.flow = function () { var self = this; - if(self._pool.length == 0) { - if(self._onEnd) + if (self._pool.length === 0) { + if (self._onEnd) self._onEnd.call(self._onEndTarget, null, []); - return; + return; } - for(var i = 0; i < self._limit; i++) + for (var i = 0; i < self._limit; i++) self._handleItem(); - } + }; + + self.onEnd = function(errors, results) { + self._finished = true; + if (self._onEnd) { + var selector = self._onEnd; + var target = self._onEndTarget; + self._onEnd = null; + self._onEndTarget = null; + selector.call(target, errors, results); + } + }; }; /** @@ -281,8 +329,8 @@ cc.async = /** @lends cc.async# */{ * @param {Object} [target] * @return {cc.AsyncPool} */ - series : function(tasks, cb, target){ - var asyncPool = new cc.AsyncPool(tasks, 1, function(func, index, cb1){ + series: function (tasks, cb, target) { + var asyncPool = new cc.AsyncPool(tasks, 1, function (func, index, cb1) { func.call(target, cb1); }, cb, target); asyncPool.flow(); @@ -296,8 +344,8 @@ cc.async = /** @lends cc.async# */{ * @param {Object} [target] * @return {cc.AsyncPool} */ - parallel : function(tasks, cb, target){ - var asyncPool = new cc.AsyncPool(tasks, 0, function(func, index, cb1){ + parallel: function (tasks, cb, target) { + var asyncPool = new cc.AsyncPool(tasks, 0, function (func, index, cb1) { func.call(target, cb1); }, cb, target); asyncPool.flow(); @@ -311,14 +359,14 @@ cc.async = /** @lends cc.async# */{ * @param {Object} [target] * @return {cc.AsyncPool} */ - waterfall : function(tasks, cb, target){ + waterfall: function (tasks, cb, target) { var args = []; var lastResults = [null];//the array to store the last results var asyncPool = new cc.AsyncPool(tasks, 1, function (func, index, cb1) { args.push(function (err) { args = Array.prototype.slice.call(arguments, 1); - if(tasks.length - 1 == index) lastResults = lastResults.concat(args);//while the last task + if (tasks.length - 1 === index) lastResults = lastResults.concat(args);//while the last task cb1.apply(null, arguments); }); func.apply(target, args); @@ -337,18 +385,18 @@ cc.async = /** @lends cc.async# */{ * Do tasks by iterator. * @param {Array|Object} tasks * @param {function|Object} iterator - * @param {function} cb callback + * @param {function} [callback] * @param {Object} [target] * @return {cc.AsyncPool} */ - map : function(tasks, iterator, cb, target){ + map: function (tasks, iterator, callback, target) { var locIterator = iterator; - if(typeof(iterator) == "object"){ - cb = iterator.cb; + if (typeof(iterator) === "object") { + callback = iterator.cb; target = iterator.iteratorTarget; locIterator = iterator.iterator; } - var asyncPool = new cc.AsyncPool(tasks, 0, locIterator, cb, target); + var asyncPool = new cc.AsyncPool(tasks, 0, locIterator, callback, target); asyncPool.flow(); return asyncPool; }, @@ -361,7 +409,7 @@ cc.async = /** @lends cc.async# */{ * @param {function} cb callback * @param {Object} [target] */ - mapLimit : function(tasks, limit, iterator, cb, target){ + mapLimit: function (tasks, limit, iterator, cb, target) { var asyncPool = new cc.AsyncPool(tasks, limit, iterator, cb, target); asyncPool.flow(); return asyncPool; @@ -374,6 +422,8 @@ cc.async = /** @lends cc.async# */{ * @class */ cc.path = /** @lends cc.path# */{ + normalizeRE: /[^\.\/]+\/\.\.\//, + /** * Join strings to be a path. * @example @@ -388,7 +438,7 @@ cc.path = /** @lends cc.path# */{ var l = arguments.length; var result = ""; for (var i = 0; i < l; i++) { - result = (result + (result == "" ? "" : "/") + arguments[i]).replace(/(\/|\\\\)$/, ""); + result = (result + (result === "" ? "" : "/") + arguments[i]).replace(/(\/|\\\\)$/, ""); } return result; }, @@ -413,11 +463,11 @@ cc.path = /** @lends cc.path# */{ * @param {string} fileName * @returns {string} */ - mainFileName: function(fileName){ - if(fileName){ - var idx = fileName.lastIndexOf("."); - if(idx !== -1) - return fileName.substring(0,idx); + mainFileName: function (fileName) { + if (fileName) { + var idx = fileName.lastIndexOf("."); + if (idx !== -1) + return fileName.substring(0, idx); } return fileName; }, @@ -441,7 +491,7 @@ cc.path = /** @lends cc.path# */{ var result = reg.exec(pathStr.replace(/(\/|\\\\)$/, "")); if (!result) return null; var baseName = result[2]; - if (extname && pathStr.substring(pathStr.length - extname.length).toLowerCase() == extname.toLowerCase()) + if (extname && pathStr.substring(pathStr.length - extname.length).toLowerCase() === extname.toLowerCase()) return baseName.substring(0, baseName.length - extname.length); return baseName; }, @@ -499,7 +549,7 @@ cc.path = /** @lends cc.path# */{ * @returns {string} */ changeBasename: function (pathStr, basename, isSameExt) { - if (basename.indexOf(".") == 0) return this.changeExtname(pathStr, basename); + if (basename.indexOf(".") === 0) return this.changeExtname(pathStr, basename); var index = pathStr.indexOf("?"); var tempStr = ""; var ext = isSameExt ? this.extname(pathStr) : ""; @@ -510,507 +560,722 @@ cc.path = /** @lends cc.path# */{ index = pathStr.lastIndexOf("/"); index = index <= 0 ? 0 : index + 1; return pathStr.substring(0, index) + basename + ext + tempStr; + }, + //todo make public after verification + _normalize: function (url) { + var oldUrl = url = String(url); + + //removing all ../ + do { + oldUrl = url; + url = url.replace(this.normalizeRE, ""); + } while (oldUrl.length !== url.length); + return url; } }; //+++++++++++++++++++++++++something about path end++++++++++++++++++++++++++++++++ //+++++++++++++++++++++++++something about loader start+++++++++++++++++++++++++++ /** - * Loader for resource loading process. It's a singleton object. + * Resource loading management. Created by in CCBoot.js as a singleton + * cc.loader. + * @name cc.Loader * @class + * @memberof cc + * @see cc.loader */ -cc.loader = /** @lends cc.loader# */{ - _jsCache: {},//cache for js - _register: {},//register of loaders - _langPathCache: {},//cache for lang path - _aliases: {},//aliases for res url - resPath: "",//root path of resource - audioPath: "",//root path of audio - cache: {},//cache for data loaded - - /** - * Get XMLHttpRequest. - * @returns {XMLHttpRequest} - */ - getXMLHttpRequest: function () { - return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("MSXML2.XMLHTTP"); +var imagePool = { + _pool: new Array(10), + _MAX: 10, + _smallImg: "data:image/gif;base64,R0lGODlhAQABAAAAACwAAAAAAQABAAA=", + + count: 0, + get: function () { + if (this.count > 0) { + this.count--; + var result = this._pool[this.count]; + this._pool[this.count] = null; + return result; + } + else { + return new Image(); + } }, + put: function (img) { + var pool = this._pool; + if (img instanceof HTMLImageElement && this.count < this._MAX) { + img.src = this._smallImg; + pool[this.count] = img; + this.count++; + } + } +}; + +/** + * Singleton instance of cc.Loader. + * @name cc.loader + * @member {cc.Loader} + * @memberof cc + */ +cc.loader = (function () { + var _jsCache = {}, //cache for js + _register = {}, //register of loaders + _langPathCache = {}, //cache for lang path + _aliases = {}, //aliases for res url + _queue = {}, // Callback queue for resources already loading + _urlRegExp = new RegExp("^(?:https?|ftp)://\\S*$", "i"); + + return /** @lends cc.Loader# */{ + /** + * Root path of resources. + * @type {String} + */ + resPath: "", + + /** + * Root path of audio resources + * @type {String} + */ + audioPath: "", + + /** + * Cache for data loaded. + * @type {Object} + */ + cache: {}, + + /** + * Get XMLHttpRequest. + * @returns {XMLHttpRequest} + */ + getXMLHttpRequest: function () { + var xhr = window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("MSXML2.XMLHTTP"); + xhr.timeout = 10000; + if (xhr.ontimeout === undefined) { + xhr._timeoutId = -1; + } + return xhr; + }, - //@MODE_BEGIN DEV + //@MODE_BEGIN DEV - _getArgs4Js: function (args) { - var a0 = args[0], a1 = args[1], a2 = args[2], results = ["", null, null]; + _getArgs4Js: function (args) { + var a0 = args[0], a1 = args[1], a2 = args[2], results = ["", null, null]; - if (args.length === 1) { - results[1] = a0 instanceof Array ? a0 : [a0]; - } else if (args.length === 2) { - if (typeof a1 == "function") { + if (args.length === 1) { results[1] = a0 instanceof Array ? a0 : [a0]; - results[2] = a1; - } else { + } else if (args.length === 2) { + if (typeof a1 === "function") { + results[1] = a0 instanceof Array ? a0 : [a0]; + results[2] = a1; + } else { + results[0] = a0 || ""; + results[1] = a1 instanceof Array ? a1 : [a1]; + } + } else if (args.length === 3) { results[0] = a0 || ""; results[1] = a1 instanceof Array ? a1 : [a1]; - } - } else if (args.length === 3) { - results[0] = a0 || ""; - results[1] = a1 instanceof Array ? a1 : [a1]; - results[2] = a2; - } else throw "arguments error to load js!"; - return results; - }, - - /** - * Load js files. - * If the third parameter doesn't exist, then the baseDir turns to be "". - * - * @param {string} [baseDir] The pre path for jsList or the list of js path. - * @param {array} jsList List of js path. - * @param {function} [cb] Callback function - * @returns {*} - */ - loadJs: function (baseDir, jsList, cb) { - var self = this, localJsCache = self._jsCache, - args = self._getArgs4Js(arguments); - - var preDir = args[0], list = args[1], callback = args[2]; - if (navigator.userAgent.indexOf("Trident/5") > -1) { - self._loadJs4Dependency(preDir, list, 0, callback); - } else { - cc.async.map(list, function (item, index, cb1) { - var jsPath = cc.path.join(preDir, item); - if (localJsCache[jsPath]) return cb1(null); - self._createScript(jsPath, false, cb1); - }, callback); - } - }, - /** - * Load js width loading image. - * - * @param {string} [baseDir] - * @param {array} jsList - * @param {function} [cb] - */ - loadJsWithImg: function (baseDir, jsList, cb) { - var self = this, jsLoadingImg = self._loadJsImg(), - args = self._getArgs4Js(arguments); - this.loadJs(args[0], args[1], function (err) { - if (err) throw err; - jsLoadingImg.parentNode.removeChild(jsLoadingImg);//remove loading gif - if (args[2]) args[2](); - }); - }, - _createScript: function (jsPath, isAsync, cb) { - var d = document, self = this, s = cc.newElement('script'); - s.async = isAsync; - s.src = jsPath; - self._jsCache[jsPath] = true; - cc._addEventListener(s, 'load', function () { - s.parentNode.removeChild(s); - this.removeEventListener('load', arguments.callee, false); - cb(); - }, false); - cc._addEventListener(s, 'error', function () { - s.parentNode.removeChild(s); - cb("Load " + jsPath + " failed!"); - }, false); - d.body.appendChild(s); - }, - _loadJs4Dependency: function (baseDir, jsList, index, cb) { - if (index >= jsList.length) { - if (cb) cb(); - return; - } - var self = this; - self._createScript(cc.path.join(baseDir, jsList[index]), false, function (err) { - if (err) return cb(err); - self._loadJs4Dependency(baseDir, jsList, index + 1, cb); - }); - }, - _loadJsImg: function () { - var d = document, jsLoadingImg = d.getElementById("cocos2d_loadJsImg"); - if (!jsLoadingImg) { - jsLoadingImg = cc.newElement('img'); - - if (cc._loadingImage) - jsLoadingImg.src = cc._loadingImage; - - var canvasNode = d.getElementById(cc.game.config["id"]); - canvasNode.style.backgroundColor = "black"; - canvasNode.parentNode.appendChild(jsLoadingImg); - - var canvasStyle = getComputedStyle ? getComputedStyle(canvasNode) : canvasNode.currentStyle; - if (!canvasStyle) - canvasStyle = {width: canvasNode.width, height: canvasNode.height}; - jsLoadingImg.style.left = canvasNode.offsetLeft + (parseFloat(canvasStyle.width) - jsLoadingImg.width) / 2 + "px"; - jsLoadingImg.style.top = canvasNode.offsetTop + (parseFloat(canvasStyle.height) - jsLoadingImg.height) / 2 + "px"; - jsLoadingImg.style.position = "absolute"; - } - return jsLoadingImg; - }, - //@MODE_END DEV - - /** - * Load a single resource as txt. - * @param {string} url - * @param {function} [cb] arguments are : err, txt - */ - loadTxt: function (url, cb) { - if (!cc._isNodeJs) { - var xhr = this.getXMLHttpRequest(), - errInfo = "load " + url + " failed!"; - xhr.open("GET", url, true); - if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) { - // IE-specific logic here - xhr.setRequestHeader("Accept-Charset", "utf-8"); - xhr.onreadystatechange = function () { - if(xhr.readyState == 4) - xhr.status == 200 ? cb(null, xhr.responseText) : cb(errInfo); - }; + results[2] = a2; + } else throw new Error("arguments error to load js!"); + return results; + }, + + isLoading: function (url) { + return (_queue[url] !== undefined); + }, + + /** + * Load js files. + * If the third parameter doesn't exist, then the baseDir turns to be "". + * + * @param {string} [baseDir] The pre path for jsList or the list of js path. + * @param {array} jsList List of js path. + * @param {function} [cb] Callback function + * @returns {*} + */ + loadJs: function (baseDir, jsList, cb) { + var self = this, + args = self._getArgs4Js(arguments); + + var preDir = args[0], list = args[1], callback = args[2]; + if (navigator.userAgent.indexOf("Trident/5") > -1) { + self._loadJs4Dependency(preDir, list, 0, callback); } else { - if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8"); - xhr.onload = function () { - if(xhr.readyState == 4) - xhr.status == 200 ? cb(null, xhr.responseText) : cb(errInfo); - }; + cc.async.map(list, function (item, index, cb1) { + var jsPath = cc.path.join(preDir, item); + if (_jsCache[jsPath]) return cb1(null); + self._createScript(jsPath, false, cb1); + }, callback); } - xhr.send(null); - } else { - var fs = require("fs"); - fs.readFile(url, function (err, data) { - err ? cb(err) : cb(null, data.toString()); + }, + /** + * Load js width loading image. + * + * @param {string} [baseDir] + * @param {array} jsList + * @param {function} [cb] + */ + loadJsWithImg: function (baseDir, jsList, cb) { + var self = this, jsLoadingImg = self._loadJsImg(), + args = self._getArgs4Js(arguments); + this.loadJs(args[0], args[1], function (err) { + if (err) throw new Error(err); + jsLoadingImg.parentNode.removeChild(jsLoadingImg);//remove loading gif + if (args[2]) args[2](); }); - } - }, - _loadTxtSync: function (url) { - if (!cc._isNodeJs) { - var xhr = this.getXMLHttpRequest(); - xhr.open("GET", url, false); - if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) { - // IE-specific logic here - xhr.setRequestHeader("Accept-Charset", "utf-8"); + }, + _createScript: function (jsPath, isAsync, cb) { + var d = document, self = this, s = document.createElement('script'); + s.async = isAsync; + _jsCache[jsPath] = true; + if (cc.game.config["noCache"] && typeof jsPath === "string") { + if (self._noCacheRex.test(jsPath)) + s.src = jsPath + "&_t=" + (new Date() - 0); + else + s.src = jsPath + "?_t=" + (new Date() - 0); } else { - if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8"); + s.src = jsPath; } - xhr.send(null); - if (!xhr.readyState == 4 || xhr.status != 200) { - return null; + s.addEventListener('load', function () { + s.parentNode.removeChild(s); + this.removeEventListener('load', arguments.callee, false); + cb(); + }, false); + s.addEventListener('error', function () { + s.parentNode.removeChild(s); + cb("Load " + jsPath + " failed!"); + }, false); + d.body.appendChild(s); + }, + _loadJs4Dependency: function (baseDir, jsList, index, cb) { + if (index >= jsList.length) { + if (cb) cb(); + return; } - return xhr.responseText; - } else { - var fs = require("fs"); - return fs.readFileSync(url).toString(); - } - }, - - loadCsb: function(url, cb){ - var xhr = new XMLHttpRequest(); - xhr.open("GET", url, true); - xhr.responseType = "arraybuffer"; - - xhr.onload = function () { - var arrayBuffer = xhr.response; // Note: not oReq.responseText - if (arrayBuffer) { - window.msg = arrayBuffer; + var self = this; + self._createScript(cc.path.join(baseDir, jsList[index]), false, function (err) { + if (err) return cb(err); + self._loadJs4Dependency(baseDir, jsList, index + 1, cb); + }); + }, + _loadJsImg: function () { + var d = document, jsLoadingImg = d.getElementById("cocos2d_loadJsImg"); + if (!jsLoadingImg) { + jsLoadingImg = document.createElement('img'); + + if (cc._loadingImage) + jsLoadingImg.src = cc._loadingImage; + + var canvasNode = d.getElementById(cc.game.config["id"]); + canvasNode.style.backgroundColor = "transparent"; + canvasNode.parentNode.appendChild(jsLoadingImg); + + var canvasStyle = getComputedStyle ? getComputedStyle(canvasNode) : canvasNode.currentStyle; + if (!canvasStyle) + canvasStyle = {width: canvasNode.width, height: canvasNode.height}; + jsLoadingImg.style.left = canvasNode.offsetLeft + (parseFloat(canvasStyle.width) - jsLoadingImg.width) / 2 + "px"; + jsLoadingImg.style.top = canvasNode.offsetTop + (parseFloat(canvasStyle.height) - jsLoadingImg.height) / 2 + "px"; + jsLoadingImg.style.position = "absolute"; } - if(xhr.readyState == 4) - xhr.status == 200 ? cb(null, xhr.response) : cb("load " + url + " failed!"); - }; + return jsLoadingImg; + }, + //@MODE_END DEV + + /** + * Load a single resource as txt. + * @param {string} url + * @param {function} [cb] arguments are : err, txt + */ + loadTxt: function (url, cb) { + if (!cc._isNodeJs) { + var xhr = this.getXMLHttpRequest(), + errInfo = "load " + url + " failed!"; + xhr.open("GET", url, true); + if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) { + // IE-specific logic here + xhr.setRequestHeader("Accept-Charset", "utf-8"); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) + (xhr.status === 200||xhr.status === 0) ? cb(null, xhr.responseText) : cb({status:xhr.status, errorMessage:errInfo}, null); + }; + } else { + if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8"); + var loadCallback = function () { + xhr.removeEventListener('load', loadCallback); + xhr.removeEventListener('error', errorCallback); + if (xhr._timeoutId >= 0) { + clearTimeout(xhr._timeoutId); + } + else { + xhr.removeEventListener('timeout', timeoutCallback); + } + if (xhr.readyState === 4) { + (xhr.status === 200||xhr.status === 0) ? cb(null, xhr.responseText) : cb({status:xhr.status, errorMessage:errInfo}, null); + } + }; + var errorCallback = function () { + xhr.removeEventListener('load', loadCallback); + xhr.removeEventListener('error', errorCallback); + if (xhr._timeoutId >= 0) { + clearTimeout(xhr._timeoutId); + } + else { + xhr.removeEventListener('timeout', timeoutCallback); + } + cb({status: xhr.status, errorMessage: errInfo}, null); + }; + var timeoutCallback = function () { + xhr.removeEventListener('load', loadCallback); + xhr.removeEventListener('error', errorCallback); + if (xhr._timeoutId >= 0) { + clearTimeout(xhr._timeoutId); + } + else { + xhr.removeEventListener('timeout', timeoutCallback); + } + cb({status: xhr.status, errorMessage: "Request timeout: " + errInfo}, null); + }; + xhr.addEventListener('load', loadCallback); + xhr.addEventListener('error', errorCallback); + if (xhr.ontimeout === undefined) { + xhr._timeoutId = setTimeout(function () { + timeoutCallback(); + }, xhr.timeout); + } + else { + xhr.addEventListener('timeout', timeoutCallback); + } + } + xhr.send(null); + } else { + var fs = require("fs"); + fs.readFile(url, function (err, data) { + err ? cb(err) : cb(null, data.toString()); + }); + } + }, - xhr.send(null); - }, + loadCsb: function(url, cb){ + var xhr = cc.loader.getXMLHttpRequest(), + errInfo = "load " + url + " failed!"; + xhr.open("GET", url, true); + xhr.responseType = "arraybuffer"; - /** - * Load a single resource as json. - * @param {string} url - * @param {function} [cb] arguments are : err, json - */ - loadJson: function (url, cb) { - this.loadTxt(url, function (err, txt) { - if (err) { - cb(err); + var loadCallback = function () { + xhr.removeEventListener('load', loadCallback); + xhr.removeEventListener('error', errorCallback); + if (xhr._timeoutId >= 0) { + clearTimeout(xhr._timeoutId); + } + else { + xhr.removeEventListener('timeout', timeoutCallback); + } + var arrayBuffer = xhr.response; // Note: not oReq.responseText + if (arrayBuffer) { + window.msg = arrayBuffer; + } + if (xhr.readyState === 4) { + (xhr.status === 200||xhr.status === 0) ? cb(null, xhr.response) : cb({status:xhr.status, errorMessage:errInfo}, null); + } + }; + var errorCallback = function(){ + xhr.removeEventListener('load', loadCallback); + xhr.removeEventListener('error', errorCallback); + if (xhr._timeoutId >= 0) { + clearTimeout(xhr._timeoutId); + } + else { + xhr.removeEventListener('timeout', timeoutCallback); + } + cb({status:xhr.status, errorMessage:errInfo}, null); + }; + var timeoutCallback = function () { + xhr.removeEventListener('load', loadCallback); + xhr.removeEventListener('error', errorCallback); + if (xhr._timeoutId >= 0) { + clearTimeout(xhr._timeoutId); + } + else { + xhr.removeEventListener('timeout', timeoutCallback); + } + cb({status: xhr.status, errorMessage: "Request timeout: " + errInfo}, null); + }; + xhr.addEventListener('load', loadCallback); + xhr.addEventListener('error', errorCallback); + if (xhr.ontimeout === undefined) { + xhr._timeoutId = setTimeout(function () { + timeoutCallback(); + }, xhr.timeout); } else { - try { - var result = JSON.parse(txt); + xhr.addEventListener('timeout', timeoutCallback); + } + xhr.send(null); + }, + + /** + * Load a single resource as json. + * @param {string} url + * @param {function} [cb] arguments are : err, json + */ + loadJson: function (url, cb) { + this.loadTxt(url, function (err, txt) { + if (err) { + cb(err); } - catch (e) { - throw "parse json [" + url + "] failed : " + e; - return; + else { + try { + var result = JSON.parse(txt); + } + catch (e) { + throw new Error("parse json [" + url + "] failed : " + e); + return; + } + cb(null, result); } - cb(null, result); + }); + }, + + _checkIsImageURL: function (url) { + var ext = /(\.png)|(\.jpg)|(\.bmp)|(\.jpeg)|(\.gif)/.exec(url); + return (ext != null); + }, + /** + * Load a single image. + * @param {!string} url + * @param {object} [option] + * @param {function} callback + * @returns {Image} + */ + loadImg: function (url, option, callback, img) { + var opt = { + isCrossOrigin: true + }; + if (callback !== undefined) + opt.isCrossOrigin = option.isCrossOrigin === undefined ? opt.isCrossOrigin : option.isCrossOrigin; + else if (option !== undefined) + callback = option; + + var texture = this.getRes(url); + if (texture) { + callback && callback(null, texture); + return null; } - }); - }, - - _checkIsImageURL: function (url) { - var ext = /(\.png)|(\.jpg)|(\.bmp)|(\.jpeg)|(\.gif)/.exec(url); - return (ext != null); - }, - /** - * Load a single image. - * @param {!string} url - * @param {object} [option] - * @param {function} cb - * @returns {Image} - */ - loadImg: function (url, option, cb) { - var opt = { - isCrossOrigin: true - }; - if (cb !== undefined) - opt.isCrossOrigin = option.isCrossOrigin == null ? opt.isCrossOrigin : option.isCrossOrigin; - else if (option !== undefined) - cb = option; - - var img = this.getRes(url); - if (img) { - cb && cb(null, img); - return img; - } - img = new Image(); - if (opt.isCrossOrigin && location.origin != "file://") - img.crossOrigin = "Anonymous"; - - var lcb = function () { - this.removeEventListener('load', lcb, false); - this.removeEventListener('error', ecb, false); - - cc.loader.cache[url] = img; - if (cb) - cb(null, img); - }; + var queue = _queue[url]; + if (queue) { + queue.callbacks.push(callback); + return queue.img; + } - var ecb = function () { - this.removeEventListener('error', ecb, false); + img = img || imagePool.get(); + if (opt.isCrossOrigin && location.origin !== "file://") + img.crossOrigin = "Anonymous"; + else + img.crossOrigin = null; + + var loadCallback = function () { + this.removeEventListener('load', loadCallback, false); + this.removeEventListener('error', errorCallback, false); + + var queue = _queue[url]; + if (queue) { + var callbacks = queue.callbacks; + for (var i = 0; i < callbacks.length; ++i) { + var cb = callbacks[i]; + if (cb) { + cb(null, img); + } + } + queue.img = null; + delete _queue[url]; + } - if(img.crossOrigin && img.crossOrigin.toLowerCase() == "anonymous"){ - opt.isCrossOrigin = false; - cc.loader.loadImg(url, opt, cb); - }else{ - typeof cb == "function" && cb("load image failed"); - } - }; + if (window.ENABLE_IMAEG_POOL && cc._renderType === cc.game.RENDER_TYPE_WEBGL) { + imagePool.put(img); + } + }; + + var self = this; + var errorCallback = function () { + this.removeEventListener('load', loadCallback, false); + this.removeEventListener('error', errorCallback, false); + + if (window.location.protocol !== 'https:' && img.crossOrigin && img.crossOrigin.toLowerCase() === "anonymous") { + opt.isCrossOrigin = false; + self.release(url); + cc.loader.loadImg(url, opt, callback, img); + } else { + var queue = _queue[url]; + if (queue) { + var callbacks = queue.callbacks; + for (var i = 0; i < callbacks.length; ++i) { + var cb = callbacks[i]; + if (cb) { + cb("load image failed"); + } + } + queue.img = null; + delete _queue[url]; + } - cc._addEventListener(img, "load", lcb); - cc._addEventListener(img, "error", ecb); - img.src = url; - return img; - }, + if (cc._renderType === cc.game.RENDER_TYPE_WEBGL) { + imagePool.put(img); + } + } + }; - /** - * Iterator function to load res - * @param {object} item - * @param {number} index - * @param {function} [cb] - * @returns {*} - * @private - */ - _loadResIterator: function (item, index, cb) { - var self = this, url = null; - var type = item.type; - if (type) { - type = "." + type.toLowerCase(); - url = item.src ? item.src : item.name + type; - } else { - url = item; - type = cc.path.extname(url); - } + _queue[url] = { + img: img, + callbacks: callback ? [callback] : [] + }; - var obj = self.getRes(url); - if (obj) - return cb(null, obj); - var loader = null; - if (type) { - loader = self._register[type.toLowerCase()]; - } - if (!loader) { - cc.error("loader for [" + type + "] not exists!"); - return cb(); - } - var basePath = loader.getBasePath ? loader.getBasePath() : self.resPath; - var realUrl = self.getUrl(basePath, url); - loader.load(realUrl, url, item, function (err, data) { - if (err) { - cc.log(err); - self.cache[url] = null; - delete self.cache[url]; - cb(); + img.addEventListener("load", loadCallback); + img.addEventListener("error", errorCallback); + img.src = url; + return img; + }, + + /** + * Iterator function to load res + * @param {object} item + * @param {number} index + * @param {function} [cb] + * @returns {*} + * @private + */ + _loadResIterator: function (item, index, cb) { + var self = this, url = null; + var type = item.type; + if (type) { + type = "." + type.toLowerCase(); + url = item.src ? item.src : item.name + type; } else { - self.cache[url] = data; - cb(null, data); + url = item; + type = cc.path.extname(url); } - }); - }, - /** - * Get url with basePath. - * @param {string} basePath - * @param {string} [url] - * @returns {*} - */ - getUrl: function (basePath, url) { - var self = this, langPathCache = self._langPathCache, path = cc.path; - if (basePath !== undefined && url === undefined) { - url = basePath; - var type = path.extname(url); - type = type ? type.toLowerCase() : ""; - var loader = self._register[type]; - if (!loader) - basePath = self.resPath; - else - basePath = loader.getBasePath ? loader.getBasePath() : self.resPath; - } - url = cc.path.join(basePath || "", url); - if (url.match(/[\/(\\\\)]lang[\/(\\\\)]/i)) { - if (langPathCache[url]) - return langPathCache[url]; - var extname = path.extname(url) || ""; - url = langPathCache[url] = url.substring(0, url.length - extname.length) + "_" + cc.sys.language + extname; - } - return url; - }, + var obj = self.getRes(url); + if (obj) + return cb(null, obj); + var loader = null; + if (type) { + loader = _register[type.toLowerCase()]; + } + if (!loader) { + cc.error("loader for [" + type + "] doesn't exist!"); + return cb(); + } + var realUrl = url; + if (!_urlRegExp.test(url)) { + var basePath = loader.getBasePath ? loader.getBasePath() : self.resPath; + realUrl = self.getUrl(basePath, url); + } - /** - * Load resources then call the callback. - * @param {string} resources - * @param {function} [option] callback or trigger - * @param {function|Object} [cb] - * @return {cc.AsyncPool} - */ - load : function(resources, option, cb){ - var self = this; - var len = arguments.length; - if(len == 0) - throw "arguments error!"; - - if(len == 3){ - if(typeof option == "function"){ - if(typeof cb == "function") - option = {trigger : option, cb : cb }; + if (cc.game.config["noCache"] && typeof realUrl === "string") { + if (self._noCacheRex.test(realUrl)) + realUrl += "&_t=" + (new Date() - 0); else - option = { cb : option, cbTarget : cb}; + realUrl += "?_t=" + (new Date() - 0); } - }else if(len == 2){ - if(typeof option == "function") - option = {cb : option}; - }else if(len == 1){ - option = {}; - } - - if(!(resources instanceof Array)) - resources = [resources]; - var asyncPool = new cc.AsyncPool(resources, 0, function(value, index, cb1, aPool){ - self._loadResIterator(value, index, function(err){ - if(err) - return cb1(err); - var arr = Array.prototype.slice.call(arguments, 1); - if(option.trigger) - option.trigger.call(option.triggerTarget, arr[0], aPool.size, aPool.finishedSize); //call trigger - cb1(null, arr[0]); - }); - }, option.cb, option.cbTarget); - asyncPool.flow(); - return asyncPool; - }, - - _handleAliases: function (fileNames, cb) { - var self = this, aliases = self._aliases; - var resList = []; - for (var key in fileNames) { - var value = fileNames[key]; - aliases[key] = value; - resList.push(value); - } - this.load(resList, cb); - }, - - /** - *

- * Loads alias map from the contents of a filename.
- *
- * @note The plist file name should follow the format below:
- *
- *
- *
- *
- * filenames
- *
- * sounds/click.wav
- * sounds/click.caf
- * sounds/endgame.wav
- * sounds/endgame.caf
- * sounds/gem-0.wav
- * sounds/gem-0.caf
- *

- * metadata
- *
- * version
- * 1
- *

- *

- *

- *

- * @param {String} url The plist file name. - * @param {Function} [cb] callback - */ - loadAliases: function (url, cb) { - var self = this, dict = self.getRes(url); - if (!dict) { - self.load(url, function (err, results) { - self._handleAliases(results[0]["filenames"], cb); + loader.load(realUrl, url, item, function (err, data) { + if (err) { + cc.log(err); + self.cache[url] = null; + delete self.cache[url]; + cb({status: 520, errorMessage: err}, null); + } else { + self.cache[url] = data; + cb(null, data); + } }); - } else - self._handleAliases(dict["filenames"], cb); - }, + }, + _noCacheRex: /\?/, + + /** + * Get url with basePath. + * @param {string} basePath + * @param {string} [url] + * @returns {*} + */ + getUrl: function (basePath, url) { + var self = this, path = cc.path; + if (basePath !== undefined && url === undefined) { + url = basePath; + var type = path.extname(url); + type = type ? type.toLowerCase() : ""; + var loader = _register[type]; + if (!loader) + basePath = self.resPath; + else + basePath = loader.getBasePath ? loader.getBasePath() : self.resPath; + } + url = cc.path.join(basePath || "", url); + if (url.match(/[\/(\\\\)]lang[\/(\\\\)]/i)) { + if (_langPathCache[url]) + return _langPathCache[url]; + var extname = path.extname(url) || ""; + url = _langPathCache[url] = url.substring(0, url.length - extname.length) + "_" + cc.sys.language + extname; + } + return url; + }, + + /** + * Load resources then call the callback. + * @param {string} resources + * @param {function} [option] callback or trigger + * @param {function|Object} [loadCallback] + * @return {cc.AsyncPool} + */ + load: function (resources, option, loadCallback) { + var self = this; + var len = arguments.length; + if (len === 0) + throw new Error("arguments error!"); + + if (len === 3) { + if (typeof option === "function") { + if (typeof loadCallback === "function") + option = {trigger: option, cb: loadCallback}; + else + option = {cb: option, cbTarget: loadCallback}; + } + } else if (len === 2) { + if (typeof option === "function") + option = {cb: option}; + } else if (len === 1) { + option = {}; + } - /** - * Register a resource loader into loader. - * @param {string} extNames - * @param {function} loader - */ - register: function (extNames, loader) { - if (!extNames || !loader) return; - var self = this; - if (typeof extNames == "string") - return this._register[extNames.trim().toLowerCase()] = loader; - for (var i = 0, li = extNames.length; i < li; i++) { - self._register["." + extNames[i].trim().toLowerCase()] = loader; + if (!(resources instanceof Array)) + resources = [resources]; + var asyncPool = new cc.AsyncPool( + resources, cc.CONCURRENCY_HTTP_REQUEST_COUNT, + function (value, index, AsyncPoolCallback, aPool) { + self._loadResIterator(value, index, function (err) { + var arr = Array.prototype.slice.call(arguments, 1); + if (option.trigger) + option.trigger.call(option.triggerTarget, arr[0], aPool.size, aPool.finishedSize); //call trigger + AsyncPoolCallback(err, arr[0]); + }); + }, + option.cb, option.cbTarget); + asyncPool.flow(); + return asyncPool; + }, + + _handleAliases: function (fileNames, cb) { + var self = this; + var resList = []; + for (var key in fileNames) { + var value = fileNames[key]; + _aliases[key] = value; + resList.push(value); + } + this.load(resList, cb); + }, + + /** + *

+ * Loads alias map from the contents of a filename.
+ *
+ * @note The plist file name should follow the format below:
+ *
+ *
+ *
+ *
+ * filenames
+ *
+ * sounds/click.wav
+ * sounds/click.caf
+ * sounds/endgame.wav
+ * sounds/endgame.caf
+ * sounds/gem-0.wav
+ * sounds/gem-0.caf
+ *

+ * metadata
+ *
+ * version
+ * 1
+ *

+ *

+ *

+ *

+ * @param {String} url The plist file name. + * @param {Function} [callback] + */ + loadAliases: function (url, callback) { + var self = this, dict = self.getRes(url); + if (!dict) { + self.load(url, function (err, results) { + self._handleAliases(results[0]["filenames"], callback); + }); + } else + self._handleAliases(dict["filenames"], callback); + }, + + /** + * Register a resource loader into loader. + * @param {string} extNames + * @param {function} loader + */ + register: function (extNames, loader) { + if (!extNames || !loader) return; + var self = this; + if (typeof extNames === "string") + return _register[extNames.trim().toLowerCase()] = loader; + for (var i = 0, li = extNames.length; i < li; i++) { + _register["." + extNames[i].trim().toLowerCase()] = loader; + } + }, + + /** + * Get resource data by url. + * @param url + * @returns {*} + */ + getRes: function (url) { + return this.cache[url] || this.cache[_aliases[url]]; + }, + + /** + * Get aliase by url. + * @param url + * @returns {*} + */ + _getAliase: function (url) { + return _aliases[url]; + }, + + /** + * Release the cache of resource by url. + * @param url + */ + release: function (url) { + var cache = this.cache; + var queue = _queue[url]; + if (queue) { + queue.img = null; + delete _queue[url]; + } + delete cache[url]; + delete cache[_aliases[url]]; + delete _aliases[url]; + }, + + /** + * Resource cache of all resources. + */ + releaseAll: function () { + var locCache = this.cache; + for (var key in locCache) + delete locCache[key]; + for (var key in _aliases) + delete _aliases[key]; } - }, - - /** - * Get resource data by url. - * @param url - * @returns {*} - */ - getRes: function (url) { - return this.cache[url] || this.cache[this._aliases[url]]; - }, - - /** - * Release the cache of resource by url. - * @param url - */ - release: function (url) { - var cache = this.cache, aliases = this._aliases; - delete cache[url]; - delete cache[aliases[url]]; - delete aliases[url]; - }, - - /** - * Resource cache of all resources. - */ - releaseAll: function () { - var locCache = this.cache, aliases = this._aliases; - for (var key in locCache) - delete locCache[key]; - for (var key in aliases) - delete aliases[key]; - } -}; + }; +})(); //+++++++++++++++++++++++++something about loader end+++++++++++++++++++++++++++++ /** @@ -1020,143 +1285,65 @@ cc.loader = /** @lends cc.loader# */{ * cc.formatStr(a, b, c); * @returns {String} */ -cc.formatStr = function(){ +cc.formatStr = function () { var args = arguments; var l = args.length; - if(l < 1) + if (l < 1) return ""; var str = args[0]; var needToFormat = true; - if(typeof str == "object"){ + if (typeof str === "object") { needToFormat = false; } - for(var i = 1; i < l; ++i){ + for (var i = 1; i < l; ++i) { var arg = args[i]; - if(needToFormat){ - while(true){ + if (needToFormat) { + while (true) { var result = null; - if(typeof arg == "number"){ + if (typeof arg === "number") { result = str.match(/(%d)|(%s)/); - if(result){ + if (result) { str = str.replace(/(%d)|(%s)/, arg); break; } } result = str.match(/%s/); - if(result) + if (result) str = str.replace(/%s/, arg); else str += " " + arg; break; } - }else + } else str += " " + arg; } return str; }; -//+++++++++++++++++++++++++something about window events begin+++++++++++++++++++++++++++ +//+++++++++++++++++++++++++Engine initialization function begin+++++++++++++++++++++++++++ (function () { - var win = window, hidden, visibilityChange, _undef = "undefined"; - if (!cc.isUndefined(document.hidden)) { - hidden = "hidden"; - visibilityChange = "visibilitychange"; - } else if (!cc.isUndefined(document.mozHidden)) { - hidden = "mozHidden"; - visibilityChange = "mozvisibilitychange"; - } else if (!cc.isUndefined(document.msHidden)) { - hidden = "msHidden"; - visibilityChange = "msvisibilitychange"; - } else if (!cc.isUndefined(document.webkitHidden)) { - hidden = "webkitHidden"; - visibilityChange = "webkitvisibilitychange"; - } - var onHidden = function () { - if (cc.eventManager && cc.game._eventHide) - cc.eventManager.dispatchEvent(cc.game._eventHide); - }; - var onShow = function () { - if (cc.eventManager && cc.game._eventShow) - cc.eventManager.dispatchEvent(cc.game._eventShow); - - if(cc.game._intervalId){ - window.cancelAnimationFrame(cc.game._intervalId); +var _tmpCanvas1 = document.createElement("canvas"), + _tmpCanvas2 = document.createElement("canvas"); - cc.game._runMainLoop(); +cc.create3DContext = function (canvas, opt_attribs) { + var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; + var context = null; + for (var ii = 0; ii < names.length; ++ii) { + try { + context = canvas.getContext(names[ii], opt_attribs); + } catch (e) { + } + if (context) { + break; } - }; - - if (hidden) { - cc._addEventListener(document, visibilityChange, function () { - if (document[hidden]) onHidden(); - else onShow(); - }, false); - } else { - cc._addEventListener(win, "blur", onHidden, false); - cc._addEventListener(win, "focus", onShow, false); - } - - if(navigator.userAgent.indexOf("MicroMessenger") > -1){ - win.onfocus = function(){ onShow() }; } + return context; +}; - if ("onpageshow" in window && "onpagehide" in window) { - cc._addEventListener(win, "pagehide", onHidden, false); - cc._addEventListener(win, "pageshow", onShow, false); - } - win = null; - visibilityChange = null; -})(); -//+++++++++++++++++++++++++something about window events end+++++++++++++++++++++++++++++ - -//+++++++++++++++++++++++++something about log start++++++++++++++++++++++++++++ - -//to make sure the cc.log, cc.warn, cc.error and cc.assert would not throw error before init by debugger mode. - -cc.log = cc.warn = cc.error = cc.assert = function () { -}; - -//+++++++++++++++++++++++++something about log end+++++++++++++++++++++++++++++ - -/** - * create a webgl context - * @param {HTMLCanvasElement} canvas - * @param {Object} opt_attribs - * @return {WebGLRenderingContext} - */ -cc.create3DContext = function (canvas, opt_attribs) { - var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; - var context = null; - for (var ii = 0; ii < names.length; ++ii) { - try { - context = canvas.getContext(names[ii], opt_attribs); - } catch (e) { - } - if (context) { - break; - } - } - return context; -}; -//+++++++++++++++++++++++++something about sys begin+++++++++++++++++++++++++++++ -cc._initSys = function (config, CONFIG_KEY) { - /** - * Canvas of render type - * @constant - * @type {Number} - */ - cc._RENDER_TYPE_CANVAS = 0; - - /** - * WebGL of render type - * @constant - * @type {Number} - */ - cc._RENDER_TYPE_WEBGL = 1; - +var _initSys = function () { /** * System variables * @namespace @@ -1301,12 +1488,14 @@ cc._initSys = function (config, CONFIG_KEY) { sys.LANGUAGE_POLISH = "pl"; /** + * Unknown language code * @memberof cc.sys - * @name OS_WINDOWS + * @name LANGUAGE_UNKNOWN * @constant - * @type {string} + * @type {Number} */ - sys.OS_WINDOWS = "Windows"; + sys.LANGUAGE_UNKNOWN = "unkonwn"; + /** * @memberof cc.sys * @name OS_IOS @@ -1316,18 +1505,25 @@ cc._initSys = function (config, CONFIG_KEY) { sys.OS_IOS = "iOS"; /** * @memberof cc.sys - * @name OS_OSX + * @name OS_ANDROID * @constant * @type {string} */ - sys.OS_OSX = "OS X"; + sys.OS_ANDROID = "Android"; /** * @memberof cc.sys - * @name OS_UNIX + * @name OS_WINDOWS * @constant * @type {string} */ - sys.OS_UNIX = "UNIX"; + sys.OS_WINDOWS = "Windows"; + /** + * @memberof cc.sys + * @name OS_MARMALADE + * @constant + * @type {string} + */ + sys.OS_MARMALADE = "Marmalade"; /** * @memberof cc.sys * @name OS_LINUX @@ -1337,11 +1533,39 @@ cc._initSys = function (config, CONFIG_KEY) { sys.OS_LINUX = "Linux"; /** * @memberof cc.sys - * @name OS_ANDROID + * @name OS_BADA * @constant * @type {string} */ - sys.OS_ANDROID = "Android"; + sys.OS_BADA = "Bada"; + /** + * @memberof cc.sys + * @name OS_BLACKBERRY + * @constant + * @type {string} + */ + sys.OS_BLACKBERRY = "Blackberry"; + /** + * @memberof cc.sys + * @name OS_OSX + * @constant + * @type {string} + */ + sys.OS_OSX = "OS X"; + /** + * @memberof cc.sys + * @name OS_WP8 + * @constant + * @type {string} + */ + sys.OS_WP8 = "WP8"; + /** + * @memberof cc.sys + * @name OS_WINRT + * @constant + * @type {string} + */ + sys.OS_WINRT = "WINRT"; /** * @memberof cc.sys * @name OS_UNKNOWN @@ -1352,12 +1576,20 @@ cc._initSys = function (config, CONFIG_KEY) { /** * @memberof cc.sys - * @name WINDOWS + * @name UNKNOWN + * @constant + * @default + * @type {Number} + */ + sys.UNKNOWN = -1; + /** + * @memberof cc.sys + * @name WIN32 * @constant * @default * @type {Number} */ - sys.WINDOWS = 0; + sys.WIN32 = 0; /** * @memberof cc.sys * @name LINUX @@ -1384,7 +1616,7 @@ cc._initSys = function (config, CONFIG_KEY) { sys.ANDROID = 3; /** * @memberof cc.sys - * @name IPHONE + * @name IOS * @constant * @default * @type {Number} @@ -1392,7 +1624,7 @@ cc._initSys = function (config, CONFIG_KEY) { sys.IPHONE = 4; /** * @memberof cc.sys - * @name IPAD + * @name IOS * @constant * @default * @type {Number} @@ -1466,6 +1698,7 @@ cc._initSys = function (config, CONFIG_KEY) { sys.BROWSER_TYPE_WECHAT = "wechat"; sys.BROWSER_TYPE_ANDROID = "androidbrowser"; sys.BROWSER_TYPE_IE = "ie"; + sys.BROWSER_TYPE_QQ_APP = "qq"; // QQ App sys.BROWSER_TYPE_QQ = "qqbrowser"; sys.BROWSER_TYPE_MOBILE_QQ = "mqqbrowser"; sys.BROWSER_TYPE_UC = "ucbrowser"; @@ -1479,6 +1712,9 @@ cc._initSys = function (config, CONFIG_KEY) { sys.BROWSER_TYPE_FIREFOX = "firefox"; sys.BROWSER_TYPE_SAFARI = "safari"; sys.BROWSER_TYPE_CHROME = "chrome"; + sys.BROWSER_TYPE_LIEBAO = "liebao"; + sys.BROWSER_TYPE_QZONE = "qzone"; + sys.BROWSER_TYPE_SOUGOU = "sogou"; sys.BROWSER_TYPE_UNKNOWN = "unknown"; /** @@ -1489,13 +1725,6 @@ cc._initSys = function (config, CONFIG_KEY) { */ sys.isNative = false; - var browserSupportWebGL = [sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, sys.BROWSER_TYPE_SAFARI]; - var osSupportWebGL = [sys.OS_IOS, sys.OS_WINDOWS, sys.OS_OSX, sys.OS_LINUX]; - var multipleAudioWhiteList = [ - sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, sys.BROWSER_TYPE_BAIDU_APP, - sys.BROWSER_TYPE_SAFARI, sys.BROWSER_TYPE_UC, sys.BROWSER_TYPE_QQ, sys.BROWSER_TYPE_MOBILE_QQ, sys.BROWSER_TYPE_IE - ]; - var win = window, nav = win.navigator, doc = document, docEle = doc.documentElement; var ua = nav.userAgent.toLowerCase(); @@ -1505,7 +1734,7 @@ cc._initSys = function (config, CONFIG_KEY) { * @name isMobile * @type {Boolean} */ - sys.isMobile = ua.indexOf('mobile') != -1 || ua.indexOf('android') != -1; + sys.isMobile = /mobile|android|iphone|ipad/.test(ua); /** * Indicate the running platform @@ -1527,36 +1756,33 @@ cc._initSys = function (config, CONFIG_KEY) { */ sys.language = currLanguage; - var browserType = sys.BROWSER_TYPE_UNKNOWN; - var browserTypes = ua.match(/micromessenger|qqbrowser|ucbrowser|360 aphone|360browser|baiduboxapp|baidubrowser|maxthon|trident|oupeng|opera|miuibrowser|firefox/i) - || ua.match(/chrome|safari/i); - if (browserTypes && browserTypes.length > 0) { - browserType = browserTypes[0].toLowerCase(); - if (browserType == 'micromessenger') { - browserType = sys.BROWSER_TYPE_WECHAT; - } else if (browserType === "safari" && (ua.match(/android.*applewebkit/))) - browserType = sys.BROWSER_TYPE_ANDROID; - else if (browserType == "trident") browserType = sys.BROWSER_TYPE_IE; - else if (browserType == "360 aphone") browserType = sys.BROWSER_TYPE_360; + // Get the os of system + var isAndroid = false, iOS = false, osVersion = '', osMainVersion = 0; + var uaResult = /android (\d+(?:\.\d+)+)/i.exec(ua) || /android (\d+(?:\.\d+)+)/i.exec(nav.platform); + if (uaResult) { + isAndroid = true; + osVersion = uaResult[1] || ''; + osMainVersion = parseInt(osVersion) || 0; + } + uaResult = /(iPad|iPhone|iPod).*OS ((\d+_?){2,3})/i.exec(ua); + if (uaResult) { + iOS = true; + osVersion = uaResult[2] || ''; + osMainVersion = parseInt(osVersion) || 0; + } + else if (/(iPhone|iPad|iPod)/.exec(nav.platform)) { + iOS = true; + osVersion = ''; + osMainVersion = 0; } - /** - * Indicate the running browser type - * @memberof cc.sys - * @name browserType - * @type {String} - */ - sys.browserType = browserType; - // Get the os of system - var iOS = ( ua.match(/(iPad|iPhone|iPod)/i) ? true : false ); - var isAndroid = ua.match(/android/i) || nav.platform.match(/android/i) ? true : false; var osName = sys.OS_UNKNOWN; - if (nav.appVersion.indexOf("Win") != -1) osName = sys.OS_WINDOWS; + if (nav.appVersion.indexOf("Win") !== -1) osName = sys.OS_WINDOWS; else if (iOS) osName = sys.OS_IOS; - else if (nav.appVersion.indexOf("Mac") != -1) osName = sys.OS_OSX; - else if (nav.appVersion.indexOf("X11") != -1) osName = sys.OS_UNIX; + else if (nav.appVersion.indexOf("Mac") !== -1) osName = sys.OS_OSX; + else if (nav.appVersion.indexOf("X11") !== -1 && nav.appVersion.indexOf("Linux") === -1) osName = sys.OS_UNIX; else if (isAndroid) osName = sys.OS_ANDROID; - else if (nav.appVersion.indexOf("Linux") != -1) osName = sys.OS_LINUX; + else if (nav.appVersion.indexOf("Linux") !== -1) osName = sys.OS_LINUX; /** * Indicate the running os name @@ -1565,68 +1791,116 @@ cc._initSys = function (config, CONFIG_KEY) { * @type {String} */ sys.os = osName; + /** + * Indicate the running os version string + * @memberof cc.sys + * @name osVersion + * @type {String} + */ + sys.osVersion = osVersion; + /** + * Indicate the running os main version number + * @memberof cc.sys + * @name osMainVersion + * @type {Number} + */ + sys.osMainVersion = osMainVersion; - sys._supportMultipleAudio = multipleAudioWhiteList.indexOf(sys.browserType) > -1; + /** + * Indicate the running browser type + * @memberof cc.sys + * @name browserType + * @type {String} + */ + sys.browserType = sys.BROWSER_TYPE_UNKNOWN; + /* Determine the browser type */ + (function(){ + var typeReg1 = /micromessenger|mqqbrowser|sogou|qzone|liebao|ucbrowser|360 aphone|360browser|baiduboxapp|baidubrowser|maxthon|mxbrowser|trident|miuibrowser/i; + var typeReg2 = /qqbrowser|qq|chrome|safari|firefox|opr|oupeng|opera/i; + var browserTypes = typeReg1.exec(ua); + if(!browserTypes) browserTypes = typeReg2.exec(ua); + var browserType = browserTypes ? browserTypes[0] : sys.BROWSER_TYPE_UNKNOWN; + if (browserType === 'micromessenger') + browserType = sys.BROWSER_TYPE_WECHAT; + else if (browserType === "safari" && isAndroid) + browserType = sys.BROWSER_TYPE_ANDROID; + else if (browserType === "trident") + browserType = sys.BROWSER_TYPE_IE; + else if (browserType === "360 aphone") + browserType = sys.BROWSER_TYPE_360; + else if (browserType === "mxbrowser") + browserType = sys.BROWSER_TYPE_MAXTHON; + else if (browserType === "opr") + browserType = sys.BROWSER_TYPE_OPERA; + sys.browserType = browserType; + })(); - //++++++++++++++++++something about cc._renderTYpe and cc._supportRender begin++++++++++++++++++++++++++++ - var userRenderMode = parseInt(config[CONFIG_KEY.renderMode]); - var renderType = cc._RENDER_TYPE_WEBGL; - var tempCanvas = cc.newElement("Canvas"); - cc._supportRender = true; - var notSupportGL = !window.WebGLRenderingContext || browserSupportWebGL.indexOf(sys.browserType) == -1 || osSupportWebGL.indexOf(sys.os) == -1; - if (userRenderMode === 1 || (userRenderMode === 0 && notSupportGL) || (location.origin == "file://")) { - renderType = cc._RENDER_TYPE_CANVAS; - } + /** + * Indicate the running browser version + * @memberof cc.sys + * @name browserVersion + * @type {String} + */ + sys.browserVersion = ""; + /* Determine the browser version number */ + (function(){ + var versionReg1 = /(mqqbrowser|micromessenger|sogou|qzone|liebao|maxthon|mxbrowser|baidu)(mobile)?(browser)?\/?([\d.]+)/i; + var versionReg2 = /(msie |rv:|firefox|chrome|ucbrowser|qq|oupeng|opera|opr|safari|miui)(mobile)?(browser)?\/?([\d.]+)/i; + var tmp = ua.match(versionReg1); + if(!tmp) tmp = ua.match(versionReg2); + sys.browserVersion = tmp ? tmp[4] : ""; + })(); + + var w = window.innerWidth || document.documentElement.clientWidth; + var h = window.innerHeight || document.documentElement.clientHeight; + var ratio = window.devicePixelRatio || 1; - sys._canUseCanvasNewBlendModes = function(){ - var canvas = document.createElement('canvas'); + /** + * Indicate the real pixel resolution of the whole game window + * @memberof cc.sys + * @name windowPixelResolution + * @type {Size} + */ + sys.windowPixelResolution = { + width: ratio * w, + height: ratio * h + }; + + sys._checkWebGLRenderMode = function () { + if (cc._renderType !== cc.game.RENDER_TYPE_WEBGL) + throw new Error("This feature supports WebGL render mode only."); + }; + + //Whether or not the Canvas BlendModes are supported. + sys._supportCanvasNewBlendModes = (function(){ + var canvas = _tmpCanvas1; canvas.width = 1; canvas.height = 1; var context = canvas.getContext('2d'); context.fillStyle = '#000'; - context.fillRect(0,0,1,1); + context.fillRect(0, 0, 1, 1); context.globalCompositeOperation = 'multiply'; - var canvas2 = document.createElement('canvas'); + var canvas2 = _tmpCanvas2; canvas2.width = 1; canvas2.height = 1; var context2 = canvas2.getContext('2d'); context2.fillStyle = '#fff'; - context2.fillRect(0,0,1,1); - + context2.fillRect(0, 0, 1, 1); context.drawImage(canvas2, 0, 0, 1, 1); - return context.getImageData(0,0,1,1).data[0] === 0; - }; + return context.getImageData(0, 0, 1, 1).data[0] === 0; + })(); - //Whether or not the Canvas BlendModes are supported. - sys._supportCanvasNewBlendModes = sys._canUseCanvasNewBlendModes(); - - if (renderType == cc._RENDER_TYPE_WEBGL) { - if (!win.WebGLRenderingContext - || !cc.create3DContext(tempCanvas, {'stencil': true, 'preserveDrawingBuffer': true })) { - if (userRenderMode == 0) renderType = cc._RENDER_TYPE_CANVAS; - else cc._supportRender = false; - } - } - - if (renderType == cc._RENDER_TYPE_CANVAS) { - try { - tempCanvas.getContext("2d"); - } catch (e) { - cc._supportRender = false; - } - } - cc._renderType = renderType; - //++++++++++++++++++something about cc._renderType and cc._supportRender end++++++++++++++++++++++++++++++ + // Adjust mobile css settings + if (cc.sys.isMobile) { + var fontStyle = document.createElement("style"); + fontStyle.type = "text/css"; + document.body.appendChild(fontStyle); - // check if browser supports Web Audio - // check Web Audio's context - try { - sys._supportWebAudio = !!(win.AudioContext || win.webkitAudioContext || win.mozAudioContext); - } catch (e) { - sys._supportWebAudio = false; + fontStyle.textContent = "body,canvas,div{ -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;" + + "-webkit-tap-highlight-color:rgba(0,0,0,0);}"; } /** @@ -1641,17 +1915,85 @@ cc._initSys = function (config, CONFIG_KEY) { localStorage.removeItem("storage"); localStorage = null; } catch (e) { - if (e.name === "SECURITY_ERR" || e.name === "QuotaExceededError") { + var warn = function () { cc.warn("Warning: localStorage isn't enabled. Please confirm browser cookie or privacy option"); - } - sys.localStorage = function () { + }; + sys.localStorage = { + getItem : warn, + setItem : warn, + removeItem : warn, + clear : warn }; } - var capabilities = sys.capabilities = {"canvas": true}; - if (cc._renderType == cc._RENDER_TYPE_WEBGL) - capabilities["opengl"] = true; - if (docEle['ontouchstart'] !== undefined || nav.msPointerEnabled) + var _supportCanvas = !!_tmpCanvas1.getContext("2d"); + var _supportWebGL = false; + if (win.WebGLRenderingContext) { + var tmpCanvas = document.createElement("CANVAS"); + try{ + var context = cc.create3DContext(tmpCanvas); + if (context) { + _supportWebGL = true; + } + + if (_supportWebGL && sys.os === sys.OS_IOS && sys.osMainVersion === 9) { + // Not activating WebGL in iOS 9 UIWebView because it may crash when entering background + if (!window.indexedDB) { + _supportWebGL = false; + } + } + + if (_supportWebGL && sys.os === sys.OS_ANDROID) { + var browserVer = parseFloat(sys.browserVersion); + switch (sys.browserType) { + case sys.BROWSER_TYPE_MOBILE_QQ: + case sys.BROWSER_TYPE_BAIDU: + case sys.BROWSER_TYPE_BAIDU_APP: + // QQ & Baidu Brwoser 6.2+ (using blink kernel) + if (browserVer >= 6.2) { + _supportWebGL = true; + } + else { + _supportWebGL = false; + } + break; + case sys.BROWSER_TYPE_CHROME: + // Chrome on android supports WebGL from v.30 + if(browserVer >= 30.0) { + _supportWebGL = true; + } else { + _supportWebGL = false; + } + break; + case sys.BROWSER_TYPE_ANDROID: + // Android 5+ default browser + if (sys.osMainVersion && sys.osMainVersion >= 5) { + _supportWebGL = true; + } + break; + case sys.BROWSER_TYPE_UNKNOWN: + case sys.BROWSER_TYPE_360: + case sys.BROWSER_TYPE_MIUI: + case sys.BROWSER_TYPE_UC: + _supportWebGL = false; + } + } + } + catch (e) {} + tmpCanvas = null; + } + + /** + * The capabilities of the current platform + * @memberof cc.sys + * @name capabilities + * @type {Object} + */ + var capabilities = sys.capabilities = { + "canvas": _supportCanvas, + "opengl": _supportWebGL + }; + if (docEle['ontouchstart'] !== undefined || doc['ontouchstart'] !== undefined || nav.msPointerEnabled) capabilities["touches"] = true; if (docEle['onmouseup'] !== undefined) capabilities["mouse"] = true; @@ -1701,6 +2043,21 @@ cc._initSys = function (config, CONFIG_KEY) { // N/A in cocos2d-html5 }; + /** + * Check whether an object is valid, + * In web engine, it will return true if the object exist + * In native engine, it will return true if the JS object and the correspond native object are both valid + * @memberof cc.sys + * @name isObjectValid + * @param {Object} obj + * @return {boolean} Validity of the object + * @function + */ + sys.isObjectValid = function (obj) { + if (obj) return true; + else return false; + }; + /** * Dump system informations * @memberof cc.sys @@ -1713,305 +2070,324 @@ cc._initSys = function (config, CONFIG_KEY) { str += "isMobile : " + self.isMobile + "\r\n"; str += "language : " + self.language + "\r\n"; str += "browserType : " + self.browserType + "\r\n"; + str += "browserVersion : " + self.browserVersion + "\r\n"; str += "capabilities : " + JSON.stringify(self.capabilities) + "\r\n"; str += "os : " + self.os + "\r\n"; + str += "osVersion : " + self.osVersion + "\r\n"; str += "platform : " + self.platform + "\r\n"; + str += "Using " + (cc._renderType === cc.game.RENDER_TYPE_WEBGL ? "WEBGL" : "CANVAS") + " renderer." + "\r\n"; cc.log(str); - } -}; - -//+++++++++++++++++++++++++something about sys end+++++++++++++++++++++++++++++ - -//+++++++++++++++++++++++++something about CCGame begin+++++++++++++++++++++++++++ - -/** - * Device oriented vertically, home button on the bottom - * @constant - * @type {Number} - */ -cc.ORIENTATION_PORTRAIT = 0; - -/** - * Device oriented vertically, home button on the top - * @constant - * @type {Number} - */ -cc.ORIENTATION_PORTRAIT_UPSIDE_DOWN = 1; + }; -/** - * Device oriented horizontally, home button on the right - * @constant - * @type {Number} - */ -cc.ORIENTATION_LANDSCAPE_LEFT = 2; + /** + * Open a url in browser + * @memberof cc.sys + * @name openURL + * @param {String} url + */ + sys.openURL = function(url){ + window.open(url); + }; -/** - * Device oriented horizontally, home button on the left - * @constant - * @type {Number} - */ -cc.ORIENTATION_LANDSCAPE_RIGHT = 3; + /** + * Get the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC. + * @memberof cc.sys + * @name now + * @return {Number} + */ + sys.now = function () { + if (Date.now) { + return Date.now(); + } + else { + return +(new Date); + } + }; +}; +_initSys(); -/** - * drawing primitive of game engine - * @type {cc.DrawingPrimitive} - */ -cc._drawingUtil = null; +_tmpCanvas1 = null; +_tmpCanvas2 = null; -/** - * main Canvas 2D/3D Context of game engine - * @type {CanvasRenderingContext2D|WebGLRenderingContext} - */ -cc._renderContext = null; +//to make sure the cc.log, cc.warn, cc.error and cc.assert would not throw error before init by debugger mode. +cc.log = cc.warn = cc.error = cc.assert = function () { +}; -/** - * main Canvas of game engine - * @type {HTMLCanvasElement} - */ -cc._canvas = null; +var _config = null, + //cache for js and module that has added into jsList to be loaded. + _jsAddedCache = {}, + _engineInitCalled = false, + _engineLoadedCallback = null; -/** - * This Div element contain all game canvas - * @type {HTMLDivElement} - */ -cc._gameDiv = null; +cc._engineLoaded = false; -cc._rendererInitialized = false; -/** - *

- * setup game main canvas,renderContext,gameDiv and drawingUtil with argument
- *
- * can receive follow type of arguemnt:
- * - empty: create a canvas append to document's body, and setup other option
- * - string: search the element by document.getElementById(),
- * if this element is HTMLCanvasElement, set this element as main canvas of engine, and set it's ParentNode as cc._gameDiv.
- * if this element is HTMLDivElement, set it's ParentNode to cc._gameDiv, and create a canvas as main canvas of engine.
- *

- * @function - * @example - * //setup with null - * cc._setup(); - * - * // setup with HTMLCanvasElement, gameCanvas is Canvas element - * // declare like this: - * cc._setup("gameCanvas"); - * - * //setup with HTMLDivElement, gameDiv is Div element - * // declare like this:
- * cc._setup("Cocos2dGameContainer"); - */ -cc._setupCalled = false; -cc._setup = function (el, width, height) { - // Avoid setup to be called twice. - if (cc._setupCalled) return; - else cc._setupCalled = true; - var win = window; - var lastTime = new Date(); - var frameTime = 1000 / cc.game.config[cc.game.CONFIG_KEY.frameRate]; - - var stTime = function(callback){ - var currTime = new Date().getTime(); - var timeToCall = Math.max(0, frameTime - (currTime - lastTime)); - var id = window.setTimeout(function() { callback(); }, - timeToCall); - lastTime = currTime + timeToCall; - return id; - }; +function _determineRenderType(config) { + var CONFIG_KEY = cc.game.CONFIG_KEY, + userRenderMode = parseInt(config[CONFIG_KEY.renderMode]) || 0; - var ctTime = function(id){ - clearTimeout(id); - }; + // Adjust RenderType + if (isNaN(userRenderMode) || userRenderMode > 2 || userRenderMode < 0) + config[CONFIG_KEY.renderMode] = 0; - if(cc.sys.os === cc.sys.OS_IOS && cc.sys.browserType === cc.sys.BROWSER_TYPE_WECHAT){ - win.requestAnimFrame = stTime; - win.cancelAnimationFrame = ctTime; - }else if(cc.game.config[cc.game.CONFIG_KEY.frameRate] != 60){ - win.requestAnimFrame = stTime; - win.cancelAnimationFrame = ctTime; - }else{ - win.requestAnimFrame = win.requestAnimationFrame || - win.webkitRequestAnimationFrame || - win.mozRequestAnimationFrame || - win.oRequestAnimationFrame || - win.msRequestAnimationFrame || - stTime; - win.cancelAnimationFrame = window.cancelAnimationFrame || - window.cancelRequestAnimationFrame || - window.msCancelRequestAnimationFrame || - window.mozCancelRequestAnimationFrame || - window.oCancelRequestAnimationFrame || - window.webkitCancelRequestAnimationFrame || - window.msCancelAnimationFrame || - window.mozCancelAnimationFrame || - window.webkitCancelAnimationFrame || - window.oCancelAnimationFrame || - ctTime; - } + // Determine RenderType + cc._renderType = cc.game.RENDER_TYPE_CANVAS; + cc._supportRender = false; - var element = cc.$(el) || cc.$('#' + el); - var localCanvas, localContainer, localConStyle; - if (element.tagName == "CANVAS") { - width = width || element.width; - height = height || element.height; - - //it is already a canvas, we wrap it around with a div - localContainer = cc.container = cc.newElement("DIV"); - localCanvas = cc._canvas = element; - localCanvas.parentNode.insertBefore(localContainer, localCanvas); - localCanvas.appendTo(localContainer); - localContainer.setAttribute('id', 'Cocos2dGameContainer'); - } else {//we must make a new canvas and place into this element - if (element.tagName != "DIV") { - cc.log("Warning: target element is not a DIV or CANVAS"); + if (userRenderMode === 0) { + if (cc.sys.capabilities["opengl"]) { + cc._renderType = cc.game.RENDER_TYPE_WEBGL; + cc._supportRender = true; + } + else if (cc.sys.capabilities["canvas"]) { + cc._renderType = cc.game.RENDER_TYPE_CANVAS; + cc._supportRender = true; } - width = width || element.clientWidth; - height = height || element.clientHeight; - localContainer = cc.container = element; - localCanvas = cc._canvas = cc.$(cc.newElement("CANVAS")); - element.appendChild(localCanvas); } + else if (userRenderMode === 1 && cc.sys.capabilities["canvas"]) { + cc._renderType = cc.game.RENDER_TYPE_CANVAS; + cc._supportRender = true; + } + else if (userRenderMode === 2 && cc.sys.capabilities["opengl"]) { + cc._renderType = cc.game.RENDER_TYPE_WEBGL; + cc._supportRender = true; + } +} + +function _getJsListOfModule(moduleMap, moduleName, dir) { + if (_jsAddedCache[moduleName]) return null; + dir = dir || ""; + var jsList = []; + var tempList = moduleMap[moduleName]; + if (!tempList) throw new Error("can not find module [" + moduleName + "]"); + var ccPath = cc.path; + for (var i = 0, li = tempList.length; i < li; i++) { + var item = tempList[i]; + if (_jsAddedCache[item]) continue; + var extname = ccPath.extname(item); + if (!extname) { + var arr = _getJsListOfModule(moduleMap, item, dir); + if (arr) jsList = jsList.concat(arr); + } else if (extname.toLowerCase() === ".js") jsList.push(ccPath.join(dir, item)); + _jsAddedCache[item] = 1; + } + return jsList; +} + +function _afterEngineLoaded(config) { + if (cc._initDebugSetting) + cc._initDebugSetting(config[cc.game.CONFIG_KEY.debugMode]); + cc._engineLoaded = true; + console.log(cc.ENGINE_VERSION); + if (_engineLoadedCallback) _engineLoadedCallback(); +} + +function _load(config) { + var self = this; + var CONFIG_KEY = cc.game.CONFIG_KEY, engineDir = config[CONFIG_KEY.engineDir], loader = cc.loader; - localCanvas.addClass("gameCanvas"); - localCanvas.setAttribute("width", width || 480); - localCanvas.setAttribute("height", height || 320); - localCanvas.setAttribute("tabindex", 99); - localCanvas.style.outline = "none"; - localConStyle = localContainer.style; - localConStyle.width = (width || 480) + "px"; - localConStyle.height = (height || 320) + "px"; - localConStyle.margin = "0 auto"; - - localConStyle.position = 'relative'; - localConStyle.overflow = 'hidden'; - localContainer.top = '100%'; - - if (cc._renderType == cc._RENDER_TYPE_WEBGL) - cc._renderContext = cc.webglContext = cc.create3DContext(localCanvas, { - 'stencil': true, - 'preserveDrawingBuffer': true, - 'antialias': !cc.sys.isMobile, - 'alpha': false}); - if (cc._renderContext) { - win.gl = cc._renderContext; // global variable declared in CCMacro.js - cc._drawingUtil = new cc.DrawingPrimitiveWebGL(cc._renderContext); - cc._rendererInitialized = true; - cc.textureCache._initializingRenderer(); - cc.shaderCache._init(); + if (cc.Class) { + // Single file loaded + _afterEngineLoaded(config); } else { - cc._renderContext = localCanvas.getContext("2d"); - cc._mainRenderContextBackup = cc._renderContext; - cc._renderContext.translate(0, localCanvas.height); - cc._drawingUtil = cc.DrawingPrimitiveCanvas ? new cc.DrawingPrimitiveCanvas(cc._renderContext) : null; + // Load cocos modules + var ccModulesPath = cc.path.join(engineDir, "moduleConfig.json"); + loader.loadJson(ccModulesPath, function (err, modulesJson) { + if (err) throw new Error(err); + var modules = config["modules"] || []; + var moduleMap = modulesJson["module"]; + var jsList = []; + if (cc.sys.capabilities["opengl"] && modules.indexOf("base4webgl") < 0) modules.splice(0, 0, "base4webgl"); + else if (modules.indexOf("core") < 0) modules.splice(0, 0, "core"); + for (var i = 0, li = modules.length; i < li; i++) { + var arr = _getJsListOfModule(moduleMap, modules[i], engineDir); + if (arr) jsList = jsList.concat(arr); + } + cc.loader.loadJsWithImg(jsList, function (err) { + if (err) throw err; + _afterEngineLoaded(config); + }); + }); } - - cc._gameDiv = localContainer; - cc.log(cc.ENGINE_VERSION); - cc._setContextMenuEnable(false); - - if (cc.sys.isMobile) { - var fontStyle = cc.newElement("style"); - fontStyle.type = "text/css"; - document.body.appendChild(fontStyle); - - fontStyle.textContent = "body,canvas,div{ -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;" - + "-webkit-tap-highlight-color:rgba(0,0,0,0);}"; +} + +function _windowLoaded() { + this.removeEventListener('load', _windowLoaded, false); + _load(cc.game.config); +} + +cc.initEngine = function (config, cb) { + if (_engineInitCalled) { + var previousCallback = _engineLoadedCallback; + _engineLoadedCallback = function () { + previousCallback && previousCallback(); + cb && cb(); + } + return; } - // Init singletons + _engineLoadedCallback = cb; - /** - * @type {cc.EGLView} - * @name cc.view - * cc.view is the shared view object. - */ - cc.view = cc.EGLView._getInstance(); - // register system events - cc.inputManager.registerSystemEvent(cc._canvas); - - /** - * @type {cc.Director} - * @name cc.director - */ - cc.director = cc.Director._getInstance(); - if (cc.director.setOpenGLView) - cc.director.setOpenGLView(cc.view); - /** - * @type {cc.Size} - * @name cc.winSize - * cc.winSize is the alias object for the size of the current game window. - */ - cc.winSize = cc.director.getWinSize(); + // Config uninitialized and given, initialize with it + if (!cc.game.config && config) { + cc.game.config = config; + } + // No config given and no config set before, load it + else if (!cc.game.config) { + cc.game._loadConfig(); + } + config = cc.game.config; - // Parsers - cc.saxParser = new cc.SAXParser(); - /** - * @type {cc.PlistParser} - * @name cc.plistParser - * A Plist Parser - */ - cc.plistParser = new cc.PlistParser(); -}; + _determineRenderType(config); -cc._checkWebGLRenderMode = function () { - if (cc._renderType !== cc._RENDER_TYPE_WEBGL) - throw "This feature supports WebGL render mode only."; + document.body ? _load(config) : cc._addEventListener(window, 'load', _windowLoaded, false); + _engineInitCalled = true; }; -cc._isContextMenuEnable = false; -/** - * enable/disable contextMenu for Canvas - * @param {Boolean} enabled - */ -cc._setContextMenuEnable = function (enabled) { - cc._isContextMenuEnable = enabled; - cc._canvas.oncontextmenu = function () { - if (!cc._isContextMenuEnable) return false; - }; -}; +})(); +//+++++++++++++++++++++++++Engine initialization function end+++++++++++++++++++++++++++++ +//+++++++++++++++++++++++++something about CCGame begin+++++++++++++++++++++++++++ /** * An object to boot the game. * @class * @name cc.game + * */ cc.game = /** @lends cc.game# */{ + /** + * Debug mode: No debugging. {@static} + * @const {Number} + * @static + */ DEBUG_MODE_NONE: 0, + /** + * Debug mode: Info, warning, error to console. + * @const {Number} + * @static + */ DEBUG_MODE_INFO: 1, + /** + * Debug mode: Warning, error to console. + * @const {Number} + * @static + */ DEBUG_MODE_WARN: 2, + /** + * Debug mode: Error to console. + * @const {Number} + * @static + */ DEBUG_MODE_ERROR: 3, + /** + * Debug mode: Info, warning, error to web page. + * @const {Number} + * @static + */ DEBUG_MODE_INFO_FOR_WEB_PAGE: 4, + /** + * Debug mode: Warning, error to web page. + * @const {Number} + * @static + */ DEBUG_MODE_WARN_FOR_WEB_PAGE: 5, + /** + * Debug mode: Error to web page. + * @const {Number} + * @static + */ DEBUG_MODE_ERROR_FOR_WEB_PAGE: 6, + /** + * Event that is fired when the game is hidden. + * @constant {String} + */ EVENT_HIDE: "game_on_hide", + /** + * Event that is fired when the game is shown. + * @constant {String} + */ EVENT_SHOW: "game_on_show", + /** + * Event that is fired when the game is resized. + * @constant {String} + */ + EVENT_RESIZE: "game_on_resize", + /** + * Event that is fired when the renderer is done being initialized. + * @constant {String} + */ + EVENT_RENDERER_INITED: "renderer_inited", + + /** @constant {Number} */ + RENDER_TYPE_CANVAS: 0, + /** @constant {Number} */ + RENDER_TYPE_WEBGL: 1, + /** @constant {Number} */ + RENDER_TYPE_OPENGL: 2, + _eventHide: null, _eventShow: null, - _onBeforeStartArr: [], /** - * Key of config + * Keys found in project.json. + * * @constant * @type {Object} + * + * @prop {String} engineDir - In debug mode, if you use the whole engine to develop your game, you should specify its relative path with "engineDir". + * @prop {String} modules - Defines which modules you will need in your game, it's useful only on web + * @prop {String} debugMode - Debug mode, see DEBUG_MODE_XXX constant definitions. + * @prop {String} exposeClassName - Expose class name to chrome debug tools + * @prop {String} showFPS - Left bottom corner fps information will show when "showFPS" equals true, otherwise it will be hide. + * @prop {String} frameRate - Sets the wanted frame rate for your game, but the real fps depends on your game implementation and the running environment. + * @prop {String} id - Sets the id of your canvas element on the web page, it's useful only on web. + * @prop {String} renderMode - Sets the renderer type, only useful on web, 0: Automatic, 1: Canvas, 2: WebGL + * @prop {String} jsList - Sets the list of js files in your game. */ CONFIG_KEY: { + width: "width", + height: "height", engineDir: "engineDir", - dependencies: "dependencies", + modules: "modules", debugMode: "debugMode", + exposeClassName: "exposeClassName", showFPS: "showFPS", frameRate: "frameRate", id: "id", renderMode: "renderMode", - jsList: "jsList", - classReleaseMode: "classReleaseMode" + jsList: "jsList" }, + // states + _paused: true,//whether the game is paused + _configLoaded: false,//whether config loaded _prepareCalled: false,//whether the prepare function has been called _prepared: false,//whether the engine has prepared - _paused: true,//whether the game is paused + _rendererInitialized: false, + + _renderContext: null, _intervalId: null,//interval target of main + _lastTime: null, + _frameTime: null, + + /** + * The outer frame of the game canvas, parent of cc.container + * @type {Object} + */ + frame: null, + /** + * The container of game canvas, equals to cc.container + * @type {Object} + */ + container: null, + /** + * The canvas of the game, equals to cc._canvas + * @type {Object} + */ + canvas: null, + /** * Config of game * @type {Object} @@ -2020,16 +2396,19 @@ cc.game = /** @lends cc.game# */{ /** * Callback when the scripts of engine have been load. - * @type {Function} + * @type {Function|null} */ onStart: null, /** * Callback when game exits. - * @type {Function} + * @type {Function|null} */ onStop: null, +//@Public Methods + +// @Game play control /** * Set frameRate of game. * @param frameRate @@ -2039,27 +2418,54 @@ cc.game = /** @lends cc.game# */{ config[CONFIG_KEY.frameRate] = frameRate; if (self._intervalId) window.cancelAnimationFrame(self._intervalId); + self._intervalId = 0; self._paused = true; + self._setAnimFrame(); self._runMainLoop(); }, - //Run game. - _runMainLoop: function () { - var self = this, callback, config = self.config, CONFIG_KEY = self.CONFIG_KEY, - director = cc.director; - director.setDisplayStats(config[CONFIG_KEY.showFPS]); + /** + * Run the game frame by frame. + */ + step: function () { + cc.director.mainLoop(); + }, - callback = function () { - if (!self._paused) { - director.mainLoop(); - if(self._intervalId) - window.cancelAnimationFrame(self._intervalId); - self._intervalId = window.requestAnimFrame(callback); - } - }; + /** + * Pause the game. + */ + pause: function () { + if (this._paused) return; + this._paused = true; + // Pause audio engine + if (cc.audioEngine) { + cc.audioEngine._pausePlaying(); + } + // Pause main loop + if (this._intervalId) + window.cancelAnimationFrame(this._intervalId); + this._intervalId = 0; + }, - window.requestAnimFrame(callback); - self._paused = false; + /** + * Resume the game from pause. + */ + resume: function () { + if (!this._paused) return; + this._paused = false; + // Resume audio engine + if (cc.audioEngine) { + cc.audioEngine._resumePlaying(); + } + // Resume main loop + this._runMainLoop(); + }, + + /** + * Check whether the game is paused. + */ + isPaused: function () { + return this._paused; }, /** @@ -2074,153 +2480,399 @@ cc.game = /** @lends cc.game# */{ }, /** - * Run game. + * End game, it will close the game window */ - run: function (id) { - var self = this; - var _run = function () { - if (id) { - self.config[self.CONFIG_KEY.id] = id; - } - if (!self._prepareCalled) { - self.prepare(function () { + end: function () { + close(); + }, + +// @Game loading + /** + * Prepare game. + * @param cb + */ + prepare: function (cb) { + var self = this, + config = self.config, + CONFIG_KEY = self.CONFIG_KEY; + + // Config loaded + if (!this._configLoaded) { + this._loadConfig(function () { + self.prepare(cb); + }); + return; + } + + // Already prepared + if (this._prepared) { + if (cb) cb(); + return; + } + // Prepare called, but not done yet + if (this._prepareCalled) { + return; + } + // Prepare never called and engine ready + if (cc._engineLoaded) { + this._prepareCalled = true; + + this._initRenderer(config[CONFIG_KEY.width], config[CONFIG_KEY.height]); + + /** + * cc.view is the shared view object. + * @type {cc.EGLView} + * @name cc.view + * @memberof cc + */ + cc.view = cc.EGLView._getInstance(); + + /** + * @type {cc.Director} + * @name cc.director + * @memberof cc + */ + cc.director = cc.Director._getInstance(); + if (cc.director.setOpenGLView) + cc.director.setOpenGLView(cc.view); + /** + * cc.winSize is the alias object for the size of the current game window. + * @type {cc.Size} + * @name cc.winSize + * @memberof cc + */ + cc.winSize = cc.director.getWinSize(); + + this._initEvents(); + + this._setAnimFrame(); + this._runMainLoop(); + + // Load game scripts + var jsList = config[CONFIG_KEY.jsList]; + if (jsList) { + cc.loader.loadJsWithImg(jsList, function (err) { + if (err) throw new Error(err); self._prepared = true; + if (cb) cb(); }); } - if (cc._supportRender) { - self._checkPrepare = setInterval(function () { - if (self._prepared) { - cc._setup(self.config[self.CONFIG_KEY.id]); - self._runMainLoop(); - self._eventHide = self._eventHide || new cc.EventCustom(self.EVENT_HIDE); - self._eventHide.setUserData(self); - self._eventShow = self._eventShow || new cc.EventCustom(self.EVENT_SHOW); - self._eventShow.setUserData(self); - self.onStart(); - clearInterval(self._checkPrepare); - } - }, 10); + else { + if (cb) cb(); } - }; - document.body ? - _run() : - cc._addEventListener(window, 'load', function () { - this.removeEventListener('load', arguments.callee, false); - _run(); - }, false); + + return; + } + + // Engine not loaded yet + cc.initEngine(this.config, function () { + self.prepare(cb); + }); }, - _initConfig: function () { - var self = this, CONFIG_KEY = self.CONFIG_KEY; - var _init = function (cfg) { - cfg[CONFIG_KEY.engineDir] = cfg[CONFIG_KEY.engineDir] || "frameworks/cocos2d-html5"; - if(cfg[CONFIG_KEY.debugMode] == null) - cfg[CONFIG_KEY.debugMode] = 0; - cfg[CONFIG_KEY.frameRate] = cfg[CONFIG_KEY.frameRate] || 60; - if(cfg[CONFIG_KEY.renderMode] == null) - cfg[CONFIG_KEY.renderMode] = 1; - return cfg; - }; - if (document["ccConfig"]) { - self.config = _init(document["ccConfig"]); - } else { - try { - var cocos_script = document.getElementsByTagName('script'); - for(var i=0;i