1 /****************************************************************************
  2  Copyright (c) 2011-2012 cocos2d-x.org
  3  Copyright (c) 2013-2015 Chukong Technologies Inc.
  4 
  5  http://www.cocos2d-x.org
  6 
  7  Permission is hereby granted, free of charge, to any person obtaining a copy
  8  of this software and associated documentation files (the "Software"), to deal
  9  in the Software without restriction, including without limitation the rights
 10  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11  copies of the Software, and to permit persons to whom the Software is
 12  furnished to do so, subject to the following conditions:
 13 
 14  The above copyright notice and this permission notice shall be included in
 15  all copies or substantial portions of the Software.
 16 
 17  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23  THE SOFTWARE.
 24  ****************************************************************************/
 25 
 26 /**
 27  * The main namespace of Cocos2d-JS, all engine core classes, functions, properties and constants are defined in this namespace
 28  * @namespace
 29  * @name cc
 30  */
 31 var cc = cc || {};
 32 cc._tmp = cc._tmp || {};
 33 cc._LogInfos = {};
 34 
 35 var _p = window;
 36 /** @expose */
 37 _p.gl;
 38 /** @expose */
 39 _p.WebGLRenderingContext;
 40 /** @expose */
 41 _p.DeviceOrientationEvent;
 42 /** @expose */
 43 _p.DeviceMotionEvent;
 44 /** @expose */
 45 _p.AudioContext;
 46 if (!_p.AudioContext) {
 47     /** @expose */
 48     _p.webkitAudioContext;
 49 }
 50 /** @expose */
 51 _p.mozAudioContext;
 52 _p = Object.prototype;
 53 /** @expose */
 54 _p._super;
 55 /** @expose */
 56 _p.ctor;
 57 _p = null;
 58 
 59 /**
 60  * Device oriented vertically, home button on the bottom
 61  * @constant
 62  * @type {Number}
 63  */
 64 cc.ORIENTATION_PORTRAIT = 0;
 65 
 66 /**
 67  * Device oriented vertically, home button on the top
 68  * @constant
 69  * @type {Number}
 70  */
 71 cc.ORIENTATION_PORTRAIT_UPSIDE_DOWN = 1;
 72 
 73 /**
 74  * Device oriented horizontally, home button on the right
 75  * @constant
 76  * @type {Number}
 77  */
 78 cc.ORIENTATION_LANDSCAPE_LEFT = 2;
 79 
 80 /**
 81  * Device oriented horizontally, home button on the left
 82  * @constant
 83  * @type {Number}
 84  */
 85 cc.ORIENTATION_LANDSCAPE_RIGHT = 3;
 86 
 87 /**
 88  * drawing primitive of game engine
 89  * @type {cc.DrawingPrimitive}
 90  */
 91 cc._drawingUtil = null;
 92 
 93 /**
 94  * main Canvas 2D/3D Context of game engine
 95  * @type {CanvasRenderingContext2D|WebGLRenderingContext}
 96  */
 97 cc._renderContext = null;
 98 cc._supportRender = false;
 99 
100 /**
101  * Main canvas of game engine
102  * @type {HTMLCanvasElement}
103  */
104 cc._canvas = null;
105 
106 /**
107  * The element contains the game canvas
108  * @type {HTMLDivElement}
109  */
110 cc.container = null;
111 cc._gameDiv = null;
112 
113 cc.newElement = function (x) {
114     return document.createElement(x);
115 };
116 
117 /**
118  * Iterate over an object or an array, executing a function for each matched element.
119  * @param {object|array} obj
120  * @param {function} iterator
121  * @param {object} [context]
122  */
123 cc.each = function (obj, iterator, context) {
124     if (!obj)
125         return;
126     if (obj instanceof Array) {
127         for (var i = 0, li = obj.length; i < li; i++) {
128             if (iterator.call(context, obj[i], i) === false)
129                 return;
130         }
131     } else {
132         for (var key in obj) {
133             if (iterator.call(context, obj[key], key) === false)
134                 return;
135         }
136     }
137 };
138 
139 /**
140  * Copy all of the properties in source objects to target object and return the target object.
141  * @param {object} target
142  * @param {object} *sources
143  * @returns {object}
144  */
145 cc.extend = function(target) {
146     var sources = arguments.length >= 2 ? Array.prototype.slice.call(arguments, 1) : [];
147 
148     cc.each(sources, function(src) {
149         for(var key in src) {
150             if (src.hasOwnProperty(key)) {
151                 target[key] = src[key];
152             }
153         }
154     });
155     return target;
156 };
157 
158 /**
159  * Check the obj whether is function or not
160  * @param {*} obj
161  * @returns {boolean}
162  */
163 cc.isFunction = function(obj) {
164     return typeof obj === 'function';
165 };
166 
167 /**
168  * Check the obj whether is number or not
169  * @param {*} obj
170  * @returns {boolean}
171  */
172 cc.isNumber = function(obj) {
173     return typeof obj === 'number' || Object.prototype.toString.call(obj) === '[object Number]';
174 };
175 
176 /**
177  * Check the obj whether is string or not
178  * @param {*} obj
179  * @returns {boolean}
180  */
181 cc.isString = function(obj) {
182     return typeof obj === 'string' || Object.prototype.toString.call(obj) === '[object String]';
183 };
184 
185 /**
186  * Check the obj whether is array or not
187  * @param {*} obj
188  * @returns {boolean}
189  */
190 cc.isArray = function(obj) {
191     return Array.isArray(obj) ||
192         (typeof obj === 'object' && Object.prototype.toString.call(obj) === '[object Array]');
193 };
194 
195 /**
196  * Check the obj whether is undefined or not
197  * @param {*} obj
198  * @returns {boolean}
199  */
200 cc.isUndefined = function(obj) {
201     return typeof obj === 'undefined';
202 };
203 
204 /**
205  * Check the obj whether is object or not
206  * @param {*} obj
207  * @returns {boolean}
208  */
209 cc.isObject = function(obj) {
210     return typeof obj === "object" && Object.prototype.toString.call(obj) === '[object Object]';
211 };
212 
213 /**
214  * Check the url whether cross origin
215  * @param {String} url
216  * @returns {boolean}
217  */
218 cc.isCrossOrigin = function (url) {
219     if (!url) {
220         cc.log("invalid URL");
221         return false;
222     }
223     var startIndex = url.indexOf("://");
224     if (startIndex === -1)
225         return false;
226 
227     var endIndex = url.indexOf("/", startIndex + 3);
228     var urlOrigin = (endIndex === -1) ? url : url.substring(0, endIndex);
229     return urlOrigin !== location.origin;
230 };
231 
232 //+++++++++++++++++++++++++something about async begin+++++++++++++++++++++++++++++++
233 /**
234  * Async Pool class, a helper of cc.async
235  * @param {Object|Array} srcObj
236  * @param {Number} limit the limit of parallel number
237  * @param {function} iterator
238  * @param {function} onEnd
239  * @param {object} target
240  * @constructor
241  */
242 cc.AsyncPool = function(srcObj, limit, iterator, onEnd, target){
243     var self = this;
244     self._srcObj = srcObj;
245     self._limit = limit;
246     self._pool = [];
247     self._iterator = iterator;
248     self._iteratorTarget = target;
249     self._onEnd = onEnd;
250     self._onEndTarget = target;
251     self._results = srcObj instanceof Array ? [] : {};
252 
253     cc.each(srcObj, function(value, index){
254         self._pool.push({index : index, value : value});
255     });
256 
257     self.size = self._pool.length;
258     self.finishedSize = 0;
259     self._workingSize = 0;
260 
261     self._limit = self._limit || self.size;
262 
263     self.onIterator = function(iterator, target){
264         self._iterator = iterator;
265         self._iteratorTarget = target;
266     };
267 
268     self.onEnd = function(endCb, endCbTarget){
269         self._onEnd = endCb;
270         self._onEndTarget = endCbTarget;
271     };
272 
273     self._handleItem = function(){
274         var self = this;
275         if(self._pool.length === 0 || self._workingSize >= self._limit)
276             return;                                                         //return directly if the array's length = 0 or the working size great equal limit number
277 
278         var item = self._pool.shift();
279         var value = item.value, index = item.index;
280         self._workingSize++;
281         self._iterator.call(self._iteratorTarget, value, index,
282             function(err) {
283 
284                 self.finishedSize++;
285                 self._workingSize--;
286 
287                 var arr = Array.prototype.slice.call(arguments, 1);
288                 self._results[this.index] = arr[0];
289                 if (self.finishedSize === self.size) {
290                     if (self._onEnd)
291                         self._onEnd.call(self._onEndTarget, null, self._results);
292                     return;
293                 }
294                 self._handleItem();
295             }.bind(item),
296             self);
297     };
298 
299     self.flow = function(){
300         var self = this;
301         if(self._pool.length === 0) {
302             if(self._onEnd)
303                 self._onEnd.call(self._onEndTarget, null, []);
304             return;
305         }
306         for(var i = 0; i < self._limit; i++)
307             self._handleItem();
308     }
309 };
310 
311 /**
312  * @class
313  */
314 cc.async = /** @lends cc.async# */{
315     /**
316      * Do tasks series.
317      * @param {Array|Object} tasks
318      * @param {function} [cb] callback
319      * @param {Object} [target]
320      * @return {cc.AsyncPool}
321      */
322     series : function(tasks, cb, target){
323         var asyncPool = new cc.AsyncPool(tasks, 1, function(func, index, cb1){
324             func.call(target, cb1);
325         }, cb, target);
326         asyncPool.flow();
327         return asyncPool;
328     },
329 
330     /**
331      * Do tasks parallel.
332      * @param {Array|Object} tasks
333      * @param {function} cb callback
334      * @param {Object} [target]
335      * @return {cc.AsyncPool}
336      */
337     parallel : function(tasks, cb, target){
338         var asyncPool = new cc.AsyncPool(tasks, 0, function(func, index, cb1){
339             func.call(target, cb1);
340         }, cb, target);
341         asyncPool.flow();
342         return asyncPool;
343     },
344 
345     /**
346      * Do tasks waterfall.
347      * @param {Array|Object} tasks
348      * @param {function} cb callback
349      * @param {Object} [target]
350      * @return {cc.AsyncPool}
351      */
352     waterfall : function(tasks, cb, target){
353         var args = [];
354         var lastResults = [null];//the array to store the last results
355         var asyncPool = new cc.AsyncPool(tasks, 1,
356             function (func, index, cb1) {
357                 args.push(function (err) {
358                     args = Array.prototype.slice.call(arguments, 1);
359                     if(tasks.length - 1 === index) lastResults = lastResults.concat(args);//while the last task
360                     cb1.apply(null, arguments);
361                 });
362                 func.apply(target, args);
363             }, function (err) {
364                 if (!cb)
365                     return;
366                 if (err)
367                     return cb.call(target, err);
368                 cb.apply(target, lastResults);
369             });
370         asyncPool.flow();
371         return asyncPool;
372     },
373 
374     /**
375      * Do tasks by iterator.
376      * @param {Array|Object} tasks
377      * @param {function|Object} iterator
378      * @param {function} [callback]
379      * @param {Object} [target]
380      * @return {cc.AsyncPool}
381      */
382     map : function(tasks, iterator, callback, target){
383         var locIterator = iterator;
384         if(typeof(iterator) === "object"){
385             callback = iterator.cb;
386             target = iterator.iteratorTarget;
387             locIterator = iterator.iterator;
388         }
389         var asyncPool = new cc.AsyncPool(tasks, 0, locIterator, callback, target);
390         asyncPool.flow();
391         return asyncPool;
392     },
393 
394     /**
395      * Do tasks by iterator limit.
396      * @param {Array|Object} tasks
397      * @param {Number} limit
398      * @param {function} iterator
399      * @param {function} cb callback
400      * @param {Object} [target]
401      */
402     mapLimit : function(tasks, limit, iterator, cb, target){
403         var asyncPool = new cc.AsyncPool(tasks, limit, iterator, cb, target);
404         asyncPool.flow();
405         return asyncPool;
406     }
407 };
408 //+++++++++++++++++++++++++something about async end+++++++++++++++++++++++++++++++++
409 
410 //+++++++++++++++++++++++++something about path begin++++++++++++++++++++++++++++++++
411 /**
412  * @class
413  */
414 cc.path = /** @lends cc.path# */{
415     normalizeRE: /[^\.\/]+\/\.\.\//,
416 
417     /**
418      * Join strings to be a path.
419      * @example
420      cc.path.join("a", "b.png");//-->"a/b.png"
421      cc.path.join("a", "b", "c.png");//-->"a/b/c.png"
422      cc.path.join("a", "b");//-->"a/b"
423      cc.path.join("a", "b", "/");//-->"a/b/"
424      cc.path.join("a", "b/", "/");//-->"a/b/"
425      * @returns {string}
426      */
427     join: function () {
428         var l = arguments.length;
429         var result = "";
430         for (var i = 0; i < l; i++) {
431             result = (result + (result === "" ? "" : "/") + arguments[i]).replace(/(\/|\\\\)$/, "");
432         }
433         return result;
434     },
435 
436     /**
437      * Get the ext name of a path.
438      * @example
439      cc.path.extname("a/b.png");//-->".png"
440      cc.path.extname("a/b.png?a=1&b=2");//-->".png"
441      cc.path.extname("a/b");//-->null
442      cc.path.extname("a/b?a=1&b=2");//-->null
443      * @param {string} pathStr
444      * @returns {*}
445      */
446     extname: function (pathStr) {
447         var temp = /(\.[^\.\/\?\\]*)(\?.*)?$/.exec(pathStr);
448         return temp ? temp[1] : null;
449     },
450 
451     /**
452      * Get the main name of a file name
453      * @param {string} fileName
454      * @returns {string}
455      */
456     mainFileName: function(fileName){
457         if(fileName){
458             var idx = fileName.lastIndexOf(".");
459             if(idx !== -1)
460                 return fileName.substring(0,idx);
461         }
462         return fileName;
463     },
464 
465     /**
466      * Get the file name of a file path.
467      * @example
468      cc.path.basename("a/b.png");//-->"b.png"
469      cc.path.basename("a/b.png?a=1&b=2");//-->"b.png"
470      cc.path.basename("a/b.png", ".png");//-->"b"
471      cc.path.basename("a/b.png?a=1&b=2", ".png");//-->"b"
472      cc.path.basename("a/b.png", ".txt");//-->"b.png"
473      * @param {string} pathStr
474      * @param {string} [extname]
475      * @returns {*}
476      */
477     basename: function (pathStr, extname) {
478         var index = pathStr.indexOf("?");
479         if (index > 0) pathStr = pathStr.substring(0, index);
480         var reg = /(\/|\\\\)([^(\/|\\\\)]+)$/g;
481         var result = reg.exec(pathStr.replace(/(\/|\\\\)$/, ""));
482         if (!result) return null;
483         var baseName = result[2];
484         if (extname && pathStr.substring(pathStr.length - extname.length).toLowerCase() === extname.toLowerCase())
485             return baseName.substring(0, baseName.length - extname.length);
486         return baseName;
487     },
488 
489     /**
490      * Get dirname of a file path.
491      * @example
492      * unix
493      cc.path.driname("a/b/c.png");//-->"a/b"
494      cc.path.driname("a/b/c.png?a=1&b=2");//-->"a/b"
495      cc.path.dirname("a/b/");//-->"a/b"
496      cc.path.dirname("c.png");//-->""
497      * windows
498      cc.path.driname("a\\b\\c.png");//-->"a\b"
499      cc.path.driname("a\\b\\c.png?a=1&b=2");//-->"a\b"
500      * @param {string} pathStr
501      * @returns {*}
502      */
503     dirname: function (pathStr) {
504         return pathStr.replace(/((.*)(\/|\\|\\\\))?(.*?\..*$)?/, '$2');
505     },
506 
507     /**
508      * Change extname of a file path.
509      * @example
510      cc.path.changeExtname("a/b.png", ".plist");//-->"a/b.plist"
511      cc.path.changeExtname("a/b.png?a=1&b=2", ".plist");//-->"a/b.plist?a=1&b=2"
512      * @param {string} pathStr
513      * @param {string} [extname]
514      * @returns {string}
515      */
516     changeExtname: function (pathStr, extname) {
517         extname = extname || "";
518         var index = pathStr.indexOf("?");
519         var tempStr = "";
520         if (index > 0) {
521             tempStr = pathStr.substring(index);
522             pathStr = pathStr.substring(0, index);
523         }
524         index = pathStr.lastIndexOf(".");
525         if (index < 0) return pathStr + extname + tempStr;
526         return pathStr.substring(0, index) + extname + tempStr;
527     },
528     /**
529      * Change file name of a file path.
530      * @example
531      cc.path.changeBasename("a/b/c.plist", "b.plist");//-->"a/b/b.plist"
532      cc.path.changeBasename("a/b/c.plist?a=1&b=2", "b.plist");//-->"a/b/b.plist?a=1&b=2"
533      cc.path.changeBasename("a/b/c.plist", ".png");//-->"a/b/c.png"
534      cc.path.changeBasename("a/b/c.plist", "b");//-->"a/b/b"
535      cc.path.changeBasename("a/b/c.plist", "b", true);//-->"a/b/b.plist"
536      * @param {String} pathStr
537      * @param {String} basename
538      * @param {Boolean} [isSameExt]
539      * @returns {string}
540      */
541     changeBasename: function (pathStr, basename, isSameExt) {
542         if (basename.indexOf(".") === 0) return this.changeExtname(pathStr, basename);
543         var index = pathStr.indexOf("?");
544         var tempStr = "";
545         var ext = isSameExt ? this.extname(pathStr) : "";
546         if (index > 0) {
547             tempStr = pathStr.substring(index);
548             pathStr = pathStr.substring(0, index);
549         }
550         index = pathStr.lastIndexOf("/");
551         index = index <= 0 ? 0 : index + 1;
552         return pathStr.substring(0, index) + basename + ext + tempStr;
553     },
554     //todo make public after verification
555     _normalize: function(url){
556         var oldUrl = url = String(url);
557 
558         //removing all ../
559         do {
560             oldUrl = url;
561             url = url.replace(this.normalizeRE, "");
562         } while(oldUrl.length !== url.length);
563         return url;
564     }
565 };
566 //+++++++++++++++++++++++++something about path end++++++++++++++++++++++++++++++++
567 
568 //+++++++++++++++++++++++++something about loader start+++++++++++++++++++++++++++
569 /**
570  * Loader for resource loading process. It's a singleton object.
571  * @class
572  */
573 cc.loader = (function () {
574     var _jsCache = {}, //cache for js
575         _register = {}, //register of loaders
576         _langPathCache = {}, //cache for lang path
577         _aliases = {}, //aliases for res url
578         _urlRegExp = new RegExp(
579             "^" +
580                 // protocol identifier
581                 "(?:(?:https?|ftp)://)" +
582                 // user:pass authentication
583                 "(?:\\S+(?::\\S*)?@)?" +
584                 "(?:" +
585                     // IP address dotted notation octets
586                     // excludes loopback network 0.0.0.0
587                     // excludes reserved space >= 224.0.0.0
588                     // excludes network & broacast addresses
589                     // (first & last IP address of each class)
590                     "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
591                     "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
592                     "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
593                 "|" +
594                     // host name
595                     "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" +
596                     // domain name
597                     "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" +
598                     // TLD identifier
599                     "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
600                 "|" +
601                     "(?:localhost)" +
602                 ")" +
603                 // port number
604                 "(?::\\d{2,5})?" +
605                 // resource path
606                 "(?:/\\S*)?" +
607             "$", "i"
608         );
609 
610     return /** @lends cc.loader# */{
611         resPath: "",//root path of resource
612         audioPath: "",//root path of audio
613         cache: {},//cache for data loaded
614 
615         /**
616          * Get XMLHttpRequest.
617          * @returns {XMLHttpRequest}
618          */
619         getXMLHttpRequest: function () {
620             return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("MSXML2.XMLHTTP");
621         },
622 
623         //@MODE_BEGIN DEV
624 
625         _getArgs4Js: function (args) {
626             var a0 = args[0], a1 = args[1], a2 = args[2], results = ["", null, null];
627 
628             if (args.length === 1) {
629                 results[1] = a0 instanceof Array ? a0 : [a0];
630             } else if (args.length === 2) {
631                 if (typeof a1 === "function") {
632                     results[1] = a0 instanceof Array ? a0 : [a0];
633                     results[2] = a1;
634                 } else {
635                     results[0] = a0 || "";
636                     results[1] = a1 instanceof Array ? a1 : [a1];
637                 }
638             } else if (args.length === 3) {
639                 results[0] = a0 || "";
640                 results[1] = a1 instanceof Array ? a1 : [a1];
641                 results[2] = a2;
642             } else throw new Error("arguments error to load js!");
643             return results;
644         },
645 
646         /**
647          * Load js files.
648          * If the third parameter doesn't exist, then the baseDir turns to be "".
649          *
650          * @param {string} [baseDir]   The pre path for jsList or the list of js path.
651          * @param {array} jsList    List of js path.
652          * @param {function} [cb]  Callback function
653          * @returns {*}
654          */
655         loadJs: function (baseDir, jsList, cb) {
656             var self = this,
657                 args = self._getArgs4Js(arguments);
658 
659             var preDir = args[0], list = args[1], callback = args[2];
660             if (navigator.userAgent.indexOf("Trident/5") > -1) {
661                 self._loadJs4Dependency(preDir, list, 0, callback);
662             } else {
663                 cc.async.map(list, function (item, index, cb1) {
664                     var jsPath = cc.path.join(preDir, item);
665                     if (_jsCache[jsPath]) return cb1(null);
666                     self._createScript(jsPath, false, cb1);
667                 }, callback);
668             }
669         },
670         /**
671          * Load js width loading image.
672          *
673          * @param {string} [baseDir]
674          * @param {array} jsList
675          * @param {function} [cb]
676          */
677         loadJsWithImg: function (baseDir, jsList, cb) {
678             var self = this, jsLoadingImg = self._loadJsImg(),
679                 args = self._getArgs4Js(arguments);
680             this.loadJs(args[0], args[1], function (err) {
681                 if (err) throw new Error(err);
682                 jsLoadingImg.parentNode.removeChild(jsLoadingImg);//remove loading gif
683                 if (args[2]) args[2]();
684             });
685         },
686         _createScript: function (jsPath, isAsync, cb) {
687             var d = document, self = this, s = document.createElement('script');
688             s.async = isAsync;
689             _jsCache[jsPath] = true;
690             if(cc.game.config["noCache"] && typeof jsPath === "string"){
691                 if(self._noCacheRex.test(jsPath))
692                     s.src = jsPath + "&_t=" + (new Date() - 0);
693                 else
694                     s.src = jsPath + "?_t=" + (new Date() - 0);
695             }else{
696                 s.src = jsPath;
697             }
698             s.addEventListener('load', function () {
699                 s.parentNode.removeChild(s);
700                 this.removeEventListener('load', arguments.callee, false);
701                 cb();
702             }, false);
703             s.addEventListener('error', function () {
704                 s.parentNode.removeChild(s);
705                 cb("Load " + jsPath + " failed!");
706             }, false);
707             d.body.appendChild(s);
708         },
709         _loadJs4Dependency: function (baseDir, jsList, index, cb) {
710             if (index >= jsList.length) {
711                 if (cb) cb();
712                 return;
713             }
714             var self = this;
715             self._createScript(cc.path.join(baseDir, jsList[index]), false, function (err) {
716                 if (err) return cb(err);
717                 self._loadJs4Dependency(baseDir, jsList, index + 1, cb);
718             });
719         },
720         _loadJsImg: function () {
721             var d = document, jsLoadingImg = d.getElementById("cocos2d_loadJsImg");
722             if (!jsLoadingImg) {
723                 jsLoadingImg = document.createElement('img');
724 
725                 if (cc._loadingImage)
726                     jsLoadingImg.src = cc._loadingImage;
727 
728                 var canvasNode = d.getElementById(cc.game.config["id"]);
729                 canvasNode.style.backgroundColor = "transparent";
730                 canvasNode.parentNode.appendChild(jsLoadingImg);
731 
732                 var canvasStyle = getComputedStyle ? getComputedStyle(canvasNode) : canvasNode.currentStyle;
733                 if (!canvasStyle)
734                     canvasStyle = {width: canvasNode.width, height: canvasNode.height};
735                 jsLoadingImg.style.left = canvasNode.offsetLeft + (parseFloat(canvasStyle.width) - jsLoadingImg.width) / 2 + "px";
736                 jsLoadingImg.style.top = canvasNode.offsetTop + (parseFloat(canvasStyle.height) - jsLoadingImg.height) / 2 + "px";
737                 jsLoadingImg.style.position = "absolute";
738             }
739             return jsLoadingImg;
740         },
741         //@MODE_END DEV
742 
743         /**
744          * Load a single resource as txt.
745          * @param {string} url
746          * @param {function} [cb] arguments are : err, txt
747          */
748         loadTxt: function (url, cb) {
749             if (!cc._isNodeJs) {
750                 var xhr = this.getXMLHttpRequest(),
751                     errInfo = "load " + url + " failed!";
752                 xhr.open("GET", url, true);
753                 if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
754                     // IE-specific logic here
755                     xhr.setRequestHeader("Accept-Charset", "utf-8");
756                     xhr.onreadystatechange = function () {
757                         if(xhr.readyState === 4)
758                             xhr.status === 200 ? cb(null, xhr.responseText) : cb({status:xhr.status, errorMessage:errInfo}, null);
759                     };
760                 } else {
761                     if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8");
762                     xhr.onload = function () {
763                         if(xhr.readyState === 4)
764                             xhr.status === 200 ? cb(null, xhr.responseText) : cb({status:xhr.status, errorMessage:errInfo}, null);
765                     };
766                     xhr.onerror = function(){
767                         cb({status:xhr.status, errorMessage:errInfo}, null);
768                     };
769                 }
770                 xhr.send(null);
771             } else {
772                 var fs = require("fs");
773                 fs.readFile(url, function (err, data) {
774                     err ? cb(err) : cb(null, data.toString());
775                 });
776             }
777         },
778         _loadTxtSync: function (url) {
779             if (!cc._isNodeJs) {
780                 var xhr = this.getXMLHttpRequest();
781                 xhr.open("GET", url, false);
782                 if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
783                     // IE-specific logic here
784                     xhr.setRequestHeader("Accept-Charset", "utf-8");
785                 } else {
786                     if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8");
787                 }
788                 xhr.send(null);
789                 if (!xhr.readyState === 4 || xhr.status !== 200) {
790                     return null;
791                 }
792                 return xhr.responseText;
793             } else {
794                 var fs = require("fs");
795                 return fs.readFileSync(url).toString();
796             }
797         },
798 
799         loadCsb: function(url, cb){
800             var xhr = new XMLHttpRequest(),
801                 errInfo = "load " + url + " failed!";
802             xhr.open("GET", url, true);
803             xhr.responseType = "arraybuffer";
804 
805             xhr.onload = function () {
806                 var arrayBuffer = xhr.response; // Note: not oReq.responseText
807                 if (arrayBuffer) {
808                     window.msg = arrayBuffer;
809                 }
810                 if(xhr.readyState === 4)
811                     xhr.status === 200 ? cb(null, xhr.response) : cb({status:xhr.status, errorMessage:errInfo}, null);
812             };
813             xhr.onerror = function(){
814                 cb({status:xhr.status, errorMessage:errInfo}, null);
815             };
816             xhr.send(null);
817         },
818 
819         /**
820          * Load a single resource as json.
821          * @param {string} url
822          * @param {function} [cb] arguments are : err, json
823          */
824         loadJson: function (url, cb) {
825             this.loadTxt(url, function (err, txt) {
826                 if (err) {
827                     cb(err);
828                 }
829                 else {
830                     try {
831                         var result = JSON.parse(txt);
832                     }
833                     catch (e) {
834                         throw new Error("parse json [" + url + "] failed : " + e);
835                         return;
836                     }
837                     cb(null, result);
838                 }
839             });
840         },
841 
842         _checkIsImageURL: function (url) {
843             var ext = /(\.png)|(\.jpg)|(\.bmp)|(\.jpeg)|(\.gif)/.exec(url);
844             return (ext != null);
845         },
846         /**
847          * Load a single image.
848          * @param {!string} url
849          * @param {object} [option]
850          * @param {function} callback
851          * @returns {Image}
852          */
853         loadImg: function (url, option, callback) {
854             var opt = {
855                 isCrossOrigin: true
856             };
857             if (callback !== undefined)
858                 opt.isCrossOrigin = option.isCrossOrigin === null ? opt.isCrossOrigin : option.isCrossOrigin;
859             else if (option !== undefined)
860                 callback = option;
861 
862             var img = this.getRes(url);
863             if (img) {
864                 callback && callback(null, img);
865                 return img;
866             }
867 
868             img = new Image();
869             if (opt.isCrossOrigin && location.origin !== "file://")
870                 img.crossOrigin = "Anonymous";
871 
872             var loadCallback = function () {
873                 this.removeEventListener('load', loadCallback, false);
874                 this.removeEventListener('error', errorCallback, false);
875 
876                 cc.loader.cache[url] = img;
877                 if (callback)
878                     callback(null, img);
879             };
880 
881             var self = this;
882             var errorCallback = function () {
883                 this.removeEventListener('error', errorCallback, false);
884 
885                 if(img.crossOrigin && img.crossOrigin.toLowerCase() === "anonymous"){
886                     opt.isCrossOrigin = false;
887                     self.release(url);
888                     cc.loader.loadImg(url, opt, callback);
889                 }else{
890                     typeof callback === "function" && callback("load image failed");
891                 }
892             };
893 
894             img.addEventListener("load", loadCallback);
895             img.addEventListener("error", errorCallback);
896             img.src = url;
897             return img;
898         },
899 
900         /**
901          * Iterator function to load res
902          * @param {object} item
903          * @param {number} index
904          * @param {function} [cb]
905          * @returns {*}
906          * @private
907          */
908         _loadResIterator: function (item, index, cb) {
909             var self = this, url = null;
910             var type = item.type;
911             if (type) {
912                 type = "." + type.toLowerCase();
913                 url = item.src ? item.src : item.name + type;
914             } else {
915                 url = item;
916                 type = cc.path.extname(url);
917             }
918 
919             var obj = self.getRes(url);
920             if (obj)
921                 return cb(null, obj);
922             var loader = null;
923             if (type) {
924                 loader = _register[type.toLowerCase()];
925             }
926             if (!loader) {
927                 cc.error("loader for [" + type + "] not exists!");
928                 return cb();
929             }
930             var realUrl = url;
931             if (!_urlRegExp.test(url))
932             {
933                 var basePath = loader.getBasePath ? loader.getBasePath() : self.resPath;
934                 realUrl = self.getUrl(basePath, url);
935             }
936 
937             if(cc.game.config["noCache"] && typeof realUrl === "string"){
938                 if(self._noCacheRex.test(realUrl))
939                     realUrl += "&_t=" + (new Date() - 0);
940                 else
941                     realUrl += "?_t=" + (new Date() - 0);
942             }
943             loader.load(realUrl, url, item, function (err, data) {
944                 if (err) {
945                     cc.log(err);
946                     self.cache[url] = null;
947                     delete self.cache[url];
948                     cb({status:520, errorMessage:err}, null);
949                 } else {
950                     self.cache[url] = data;
951                     cb(null, data);
952                 }
953             });
954         },
955         _noCacheRex: /\?/,
956 
957         /**
958          * Get url with basePath.
959          * @param {string} basePath
960          * @param {string} [url]
961          * @returns {*}
962          */
963         getUrl: function (basePath, url) {
964             var self = this, path = cc.path;
965             if (basePath !== undefined && url === undefined) {
966                 url = basePath;
967                 var type = path.extname(url);
968                 type = type ? type.toLowerCase() : "";
969                 var loader = _register[type];
970                 if (!loader)
971                     basePath = self.resPath;
972                 else
973                     basePath = loader.getBasePath ? loader.getBasePath() : self.resPath;
974             }
975             url = cc.path.join(basePath || "", url);
976             if (url.match(/[\/(\\\\)]lang[\/(\\\\)]/i)) {
977                 if (_langPathCache[url])
978                     return _langPathCache[url];
979                 var extname = path.extname(url) || "";
980                 url = _langPathCache[url] = url.substring(0, url.length - extname.length) + "_" + cc.sys.language + extname;
981             }
982             return url;
983         },
984 
985         /**
986          * Load resources then call the callback.
987          * @param {string} resources
988          * @param {function} [option] callback or trigger
989          * @param {function|Object} [loadCallback]
990          * @return {cc.AsyncPool}
991          */
992         load : function(resources, option, loadCallback){
993             var self = this;
994             var len = arguments.length;
995             if(len === 0)
996                 throw new Error("arguments error!");
997 
998             if(len === 3){
999                 if(typeof option === "function"){
1000                     if(typeof loadCallback === "function")
1001                         option = {trigger : option, cb : loadCallback };
1002                     else
1003                         option = { cb : option, cbTarget : loadCallback};
1004                 }
1005             }else if(len === 2){
1006                 if(typeof option === "function")
1007                     option = {cb : option};
1008             }else if(len === 1){
1009                 option = {};
1010             }
1011 
1012             if(!(resources instanceof Array))
1013                 resources = [resources];
1014             var asyncPool = new cc.AsyncPool(
1015                 resources, 0,
1016                 function (value, index, AsyncPoolCallback, aPool) {
1017                     self._loadResIterator(value, index, function (err) {
1018                         var arr = Array.prototype.slice.call(arguments, 1);
1019                         if (option.trigger)
1020                             option.trigger.call(option.triggerTarget, arr[0], aPool.size, aPool.finishedSize);   //call trigger
1021                         AsyncPoolCallback(err, arr[0]);
1022                     });
1023                 },
1024                 option.cb, option.cbTarget);
1025             asyncPool.flow();
1026             return asyncPool;
1027         },
1028 
1029         _handleAliases: function (fileNames, cb) {
1030             var self = this;
1031             var resList = [];
1032             for (var key in fileNames) {
1033                 var value = fileNames[key];
1034                 _aliases[key] = value;
1035                 resList.push(value);
1036             }
1037             this.load(resList, cb);
1038         },
1039 
1040         /**
1041          * <p>
1042          *     Loads alias map from the contents of a filename.                                        <br/>
1043          *                                                                                                                 <br/>
1044          *     @note The plist file name should follow the format below:                                                   <br/>
1045          *     <?xml version="1.0" encoding="UTF-8"?>                                                                      <br/>
1046          *         <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">  <br/>
1047          *             <plist version="1.0">                                                                               <br/>
1048          *                 <dict>                                                                                          <br/>
1049          *                     <key>filenames</key>                                                                        <br/>
1050          *                     <dict>                                                                                      <br/>
1051          *                         <key>sounds/click.wav</key>                                                             <br/>
1052          *                         <string>sounds/click.caf</string>                                                       <br/>
1053          *                         <key>sounds/endgame.wav</key>                                                           <br/>
1054          *                         <string>sounds/endgame.caf</string>                                                     <br/>
1055          *                         <key>sounds/gem-0.wav</key>                                                             <br/>
1056          *                         <string>sounds/gem-0.caf</string>                                                       <br/>
1057          *                     </dict>                                                                                     <br/>
1058          *                     <key>metadata</key>                                                                         <br/>
1059          *                     <dict>                                                                                      <br/>
1060          *                         <key>version</key>                                                                      <br/>
1061          *                         <integer>1</integer>                                                                    <br/>
1062          *                     </dict>                                                                                     <br/>
1063          *                 </dict>                                                                                         <br/>
1064          *              </plist>                                                                                           <br/>
1065          * </p>
1066          * @param {String} url  The plist file name.
1067          * @param {Function} [callback]
1068          */
1069         loadAliases: function (url, callback) {
1070             var self = this, dict = self.getRes(url);
1071             if (!dict) {
1072                 self.load(url, function (err, results) {
1073                     self._handleAliases(results[0]["filenames"], callback);
1074                 });
1075             } else
1076                 self._handleAliases(dict["filenames"], callback);
1077         },
1078 
1079         /**
1080          * Register a resource loader into loader.
1081          * @param {string} extNames
1082          * @param {function} loader
1083          */
1084         register: function (extNames, loader) {
1085             if (!extNames || !loader) return;
1086             var self = this;
1087             if (typeof extNames === "string")
1088                 return _register[extNames.trim().toLowerCase()] = loader;
1089             for (var i = 0, li = extNames.length; i < li; i++) {
1090                 _register["." + extNames[i].trim().toLowerCase()] = loader;
1091             }
1092         },
1093 
1094         /**
1095          * Get resource data by url.
1096          * @param url
1097          * @returns {*}
1098          */
1099         getRes: function (url) {
1100             return this.cache[url] || this.cache[_aliases[url]];
1101         },
1102 
1103         /**
1104          * Get aliase by url.
1105          * @param url
1106          * @returns {*}
1107          */
1108         _getAliase: function (url) {
1109             return _aliases[url];
1110         },
1111 
1112         /**
1113          * Release the cache of resource by url.
1114          * @param url
1115          */
1116         release: function (url) {
1117             var cache = this.cache;
1118             delete cache[url];
1119             delete cache[_aliases[url]];
1120             delete _aliases[url];
1121         },
1122 
1123         /**
1124          * Resource cache of all resources.
1125          */
1126         releaseAll: function () {
1127             var locCache = this.cache;
1128             for (var key in locCache)
1129                 delete locCache[key];
1130             for (var key in _aliases)
1131                 delete _aliases[key];
1132         }
1133     };
1134 })();
1135 //+++++++++++++++++++++++++something about loader end+++++++++++++++++++++++++++++
1136 
1137 /**
1138  * A string tool to construct a string with format string.
1139  * for example:
1140  *      cc.formatStr("a: %d, b: %b", a, b);
1141  *      cc.formatStr(a, b, c);
1142  * @returns {String}
1143  */
1144 cc.formatStr = function(){
1145     var args = arguments;
1146     var l = args.length;
1147     if(l < 1)
1148         return "";
1149 
1150     var str = args[0];
1151     var needToFormat = true;
1152     if(typeof str === "object"){
1153         needToFormat = false;
1154     }
1155     for(var i = 1; i < l; ++i){
1156         var arg = args[i];
1157         if(needToFormat){
1158             while(true){
1159                 var result = null;
1160                 if(typeof arg === "number"){
1161                     result = str.match(/(%d)|(%s)/);
1162                     if(result){
1163                         str = str.replace(/(%d)|(%s)/, arg);
1164                         break;
1165                     }
1166                 }
1167                 result = str.match(/%s/);
1168                 if(result)
1169                     str = str.replace(/%s/, arg);
1170                 else
1171                     str += "    " + arg;
1172                 break;
1173             }
1174         }else
1175             str += "    " + arg;
1176     }
1177     return str;
1178 };
1179 
1180 
1181 //+++++++++++++++++++++++++Engine initialization function begin+++++++++++++++++++++++++++
1182 (function () {
1183 
1184 var _tmpCanvas1 = document.createElement("canvas"),
1185     _tmpCanvas2 = document.createElement("canvas");
1186 
1187 cc.create3DContext = function (canvas, opt_attribs) {
1188     var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
1189     var context = null;
1190     for (var ii = 0; ii < names.length; ++ii) {
1191         try {
1192             context = canvas.getContext(names[ii], opt_attribs);
1193         } catch (e) {
1194         }
1195         if (context) {
1196             break;
1197         }
1198     }
1199     return context;
1200 };
1201 
1202 var _initSys = function () {
1203     /**
1204      * System variables
1205      * @namespace
1206      * @name cc.sys
1207      */
1208     cc.sys = {};
1209     var sys = cc.sys;
1210 
1211     /**
1212      * English language code
1213      * @memberof cc.sys
1214      * @name LANGUAGE_ENGLISH
1215      * @constant
1216      * @type {Number}
1217      */
1218     sys.LANGUAGE_ENGLISH = "en";
1219 
1220     /**
1221      * Chinese language code
1222      * @memberof cc.sys
1223      * @name LANGUAGE_CHINESE
1224      * @constant
1225      * @type {Number}
1226      */
1227     sys.LANGUAGE_CHINESE = "zh";
1228 
1229     /**
1230      * French language code
1231      * @memberof cc.sys
1232      * @name LANGUAGE_FRENCH
1233      * @constant
1234      * @type {Number}
1235      */
1236     sys.LANGUAGE_FRENCH = "fr";
1237 
1238     /**
1239      * Italian language code
1240      * @memberof cc.sys
1241      * @name LANGUAGE_ITALIAN
1242      * @constant
1243      * @type {Number}
1244      */
1245     sys.LANGUAGE_ITALIAN = "it";
1246 
1247     /**
1248      * German language code
1249      * @memberof cc.sys
1250      * @name LANGUAGE_GERMAN
1251      * @constant
1252      * @type {Number}
1253      */
1254     sys.LANGUAGE_GERMAN = "de";
1255 
1256     /**
1257      * Spanish language code
1258      * @memberof cc.sys
1259      * @name LANGUAGE_SPANISH
1260      * @constant
1261      * @type {Number}
1262      */
1263     sys.LANGUAGE_SPANISH = "es";
1264 
1265     /**
1266      * Spanish language code
1267      * @memberof cc.sys
1268      * @name LANGUAGE_DUTCH
1269      * @constant
1270      * @type {Number}
1271      */
1272     sys.LANGUAGE_DUTCH = "du";
1273 
1274     /**
1275      * Russian language code
1276      * @memberof cc.sys
1277      * @name LANGUAGE_RUSSIAN
1278      * @constant
1279      * @type {Number}
1280      */
1281     sys.LANGUAGE_RUSSIAN = "ru";
1282 
1283     /**
1284      * Korean language code
1285      * @memberof cc.sys
1286      * @name LANGUAGE_KOREAN
1287      * @constant
1288      * @type {Number}
1289      */
1290     sys.LANGUAGE_KOREAN = "ko";
1291 
1292     /**
1293      * Japanese language code
1294      * @memberof cc.sys
1295      * @name LANGUAGE_JAPANESE
1296      * @constant
1297      * @type {Number}
1298      */
1299     sys.LANGUAGE_JAPANESE = "ja";
1300 
1301     /**
1302      * Hungarian language code
1303      * @memberof cc.sys
1304      * @name LANGUAGE_HUNGARIAN
1305      * @constant
1306      * @type {Number}
1307      */
1308     sys.LANGUAGE_HUNGARIAN = "hu";
1309 
1310     /**
1311      * Portuguese language code
1312      * @memberof cc.sys
1313      * @name LANGUAGE_PORTUGUESE
1314      * @constant
1315      * @type {Number}
1316      */
1317     sys.LANGUAGE_PORTUGUESE = "pt";
1318 
1319     /**
1320      * Arabic language code
1321      * @memberof cc.sys
1322      * @name LANGUAGE_ARABIC
1323      * @constant
1324      * @type {Number}
1325      */
1326     sys.LANGUAGE_ARABIC = "ar";
1327 
1328     /**
1329      * Norwegian language code
1330      * @memberof cc.sys
1331      * @name LANGUAGE_NORWEGIAN
1332      * @constant
1333      * @type {Number}
1334      */
1335     sys.LANGUAGE_NORWEGIAN = "no";
1336 
1337     /**
1338      * Polish language code
1339      * @memberof cc.sys
1340      * @name LANGUAGE_POLISH
1341      * @constant
1342      * @type {Number}
1343      */
1344     sys.LANGUAGE_POLISH = "pl";
1345 
1346     /**
1347      * Unknown language code
1348      * @memberof cc.sys
1349      * @name LANGUAGE_UNKNOWN
1350      * @constant
1351      * @type {Number}
1352      */
1353     sys.LANGUAGE_UNKNOWN = "unkonwn";
1354 
1355     /**
1356      * @memberof cc.sys
1357      * @name OS_IOS
1358      * @constant
1359      * @type {string}
1360      */
1361     sys.OS_IOS = "iOS";
1362     /**
1363      * @memberof cc.sys
1364      * @name OS_ANDROID
1365      * @constant
1366      * @type {string}
1367      */
1368     sys.OS_ANDROID = "Android";
1369     /**
1370      * @memberof cc.sys
1371      * @name OS_WINDOWS
1372      * @constant
1373      * @type {string}
1374      */
1375     sys.OS_WINDOWS = "Windows";
1376     /**
1377      * @memberof cc.sys
1378      * @name OS_MARMALADE
1379      * @constant
1380      * @type {string}
1381      */
1382     sys.OS_MARMALADE = "Marmalade";
1383     /**
1384      * @memberof cc.sys
1385      * @name OS_LINUX
1386      * @constant
1387      * @type {string}
1388      */
1389     sys.OS_LINUX = "Linux";
1390     /**
1391      * @memberof cc.sys
1392      * @name OS_BADA
1393      * @constant
1394      * @type {string}
1395      */
1396     sys.OS_BADA = "Bada";
1397     /**
1398      * @memberof cc.sys
1399      * @name OS_BLACKBERRY
1400      * @constant
1401      * @type {string}
1402      */
1403     sys.OS_BLACKBERRY = "Blackberry";
1404     /**
1405      * @memberof cc.sys
1406      * @name OS_OSX
1407      * @constant
1408      * @type {string}
1409      */
1410     sys.OS_OSX = "OS X";
1411     /**
1412      * @memberof cc.sys
1413      * @name OS_WP8
1414      * @constant
1415      * @type {string}
1416      */
1417     sys.OS_WP8 = "WP8";
1418     /**
1419      * @memberof cc.sys
1420      * @name OS_WINRT
1421      * @constant
1422      * @type {string}
1423      */
1424     sys.OS_WINRT = "WINRT";
1425     /**
1426      * @memberof cc.sys
1427      * @name OS_UNKNOWN
1428      * @constant
1429      * @type {string}
1430      */
1431     sys.OS_UNKNOWN = "Unknown";
1432 
1433     /**
1434      * @memberof cc.sys
1435      * @name UNKNOWN
1436      * @constant
1437      * @default
1438      * @type {Number}
1439      */
1440     sys.UNKNOWN = -1;
1441     /**
1442      * @memberof cc.sys
1443      * @name WIN32
1444      * @constant
1445      * @default
1446      * @type {Number}
1447      */
1448     sys.WIN32 = 0;
1449     /**
1450      * @memberof cc.sys
1451      * @name LINUX
1452      * @constant
1453      * @default
1454      * @type {Number}
1455      */
1456     sys.LINUX = 1;
1457     /**
1458      * @memberof cc.sys
1459      * @name MACOS
1460      * @constant
1461      * @default
1462      * @type {Number}
1463      */
1464     sys.MACOS = 2;
1465     /**
1466      * @memberof cc.sys
1467      * @name ANDROID
1468      * @constant
1469      * @default
1470      * @type {Number}
1471      */
1472     sys.ANDROID = 3;
1473     /**
1474      * @memberof cc.sys
1475      * @name IOS
1476      * @constant
1477      * @default
1478      * @type {Number}
1479      */
1480     sys.IPHONE = 4;
1481     /**
1482      * @memberof cc.sys
1483      * @name IOS
1484      * @constant
1485      * @default
1486      * @type {Number}
1487      */
1488     sys.IPAD = 5;
1489     /**
1490      * @memberof cc.sys
1491      * @name BLACKBERRY
1492      * @constant
1493      * @default
1494      * @type {Number}
1495      */
1496     sys.BLACKBERRY = 6;
1497     /**
1498      * @memberof cc.sys
1499      * @name NACL
1500      * @constant
1501      * @default
1502      * @type {Number}
1503      */
1504     sys.NACL = 7;
1505     /**
1506      * @memberof cc.sys
1507      * @name EMSCRIPTEN
1508      * @constant
1509      * @default
1510      * @type {Number}
1511      */
1512     sys.EMSCRIPTEN = 8;
1513     /**
1514      * @memberof cc.sys
1515      * @name TIZEN
1516      * @constant
1517      * @default
1518      * @type {Number}
1519      */
1520     sys.TIZEN = 9;
1521     /**
1522      * @memberof cc.sys
1523      * @name WINRT
1524      * @constant
1525      * @default
1526      * @type {Number}
1527      */
1528     sys.WINRT = 10;
1529     /**
1530      * @memberof cc.sys
1531      * @name WP8
1532      * @constant
1533      * @default
1534      * @type {Number}
1535      */
1536     sys.WP8 = 11;
1537     /**
1538      * @memberof cc.sys
1539      * @name MOBILE_BROWSER
1540      * @constant
1541      * @default
1542      * @type {Number}
1543      */
1544     sys.MOBILE_BROWSER = 100;
1545     /**
1546      * @memberof cc.sys
1547      * @name DESKTOP_BROWSER
1548      * @constant
1549      * @default
1550      * @type {Number}
1551      */
1552     sys.DESKTOP_BROWSER = 101;
1553 
1554     sys.BROWSER_TYPE_WECHAT = "wechat";
1555     sys.BROWSER_TYPE_ANDROID = "androidbrowser";
1556     sys.BROWSER_TYPE_IE = "ie";
1557     sys.BROWSER_TYPE_QQ = "qqbrowser";
1558     sys.BROWSER_TYPE_MOBILE_QQ = "mqqbrowser";
1559     sys.BROWSER_TYPE_UC = "ucbrowser";
1560     sys.BROWSER_TYPE_360 = "360browser";
1561     sys.BROWSER_TYPE_BAIDU_APP = "baiduboxapp";
1562     sys.BROWSER_TYPE_BAIDU = "baidubrowser";
1563     sys.BROWSER_TYPE_MAXTHON = "maxthon";
1564     sys.BROWSER_TYPE_OPERA = "opera";
1565     sys.BROWSER_TYPE_OUPENG = "oupeng";
1566     sys.BROWSER_TYPE_MIUI = "miuibrowser";
1567     sys.BROWSER_TYPE_FIREFOX = "firefox";
1568     sys.BROWSER_TYPE_SAFARI = "safari";
1569     sys.BROWSER_TYPE_CHROME = "chrome";
1570     sys.BROWSER_TYPE_LIEBAO = "liebao";
1571     sys.BROWSER_TYPE_QZONE = "qzone";
1572     sys.BROWSER_TYPE_SOUGOU = "sogou";
1573     sys.BROWSER_TYPE_UNKNOWN = "unknown";
1574 
1575     /**
1576      * Is native ? This is set to be true in jsb auto.
1577      * @memberof cc.sys
1578      * @name isNative
1579      * @type {Boolean}
1580      */
1581     sys.isNative = false;
1582 
1583     var win = window, nav = win.navigator, doc = document, docEle = doc.documentElement;
1584     var ua = nav.userAgent.toLowerCase();
1585 
1586     /**
1587      * Indicate whether system is mobile system
1588      * @memberof cc.sys
1589      * @name isMobile
1590      * @type {Boolean}
1591      */
1592     sys.isMobile = ua.indexOf('mobile') !== -1 || ua.indexOf('android') !== -1;
1593 
1594     /**
1595      * Indicate the running platform
1596      * @memberof cc.sys
1597      * @name platform
1598      * @type {Number}
1599      */
1600     sys.platform = sys.isMobile ? sys.MOBILE_BROWSER : sys.DESKTOP_BROWSER;
1601 
1602     var currLanguage = nav.language;
1603     currLanguage = currLanguage ? currLanguage : nav.browserLanguage;
1604     currLanguage = currLanguage ? currLanguage.split("-")[0] : sys.LANGUAGE_ENGLISH;
1605 
1606     /**
1607      * Indicate the current language of the running system
1608      * @memberof cc.sys
1609      * @name language
1610      * @type {String}
1611      */
1612     sys.language = currLanguage;
1613 
1614     // Get the os of system
1615     var isAndroid = false, iOS = false, osVersion = '', osMainVersion = 0;
1616     var uaResult = /android (\d+(?:\.\d+)+)/i.exec(ua) || /android (\d+(?:\.\d+)+)/i.exec(nav.platform);
1617     if (uaResult) {
1618         isAndroid = true;
1619         osVersion = uaResult[1] || '';
1620         osMainVersion = parseInt(osVersion) || 0;
1621     }
1622     uaResult = /(iPad|iPhone|iPod).*OS ((\d+_?){2,3})/i.exec(ua);
1623     if (uaResult) {
1624         iOS = true;
1625         osVersion = uaResult[2] || '';
1626         osMainVersion = parseInt(osVersion) || 0;
1627     }
1628 
1629     var osName = sys.OS_UNKNOWN;
1630     if (nav.appVersion.indexOf("Win") !== -1) osName = sys.OS_WINDOWS;
1631     else if (iOS) osName = sys.OS_IOS;
1632     else if (nav.appVersion.indexOf("Mac") !== -1) osName = sys.OS_OSX;
1633     else if (nav.appVersion.indexOf("X11") !== -1 && nav.appVersion.indexOf("Linux") === -1) osName = sys.OS_UNIX;
1634     else if (isAndroid) osName = sys.OS_ANDROID;
1635     else if (nav.appVersion.indexOf("Linux") !== -1) osName = sys.OS_LINUX;
1636 
1637     /**
1638      * Indicate the running os name
1639      * @memberof cc.sys
1640      * @name os
1641      * @type {String}
1642      */
1643     sys.os = osName;
1644     /**
1645      * Indicate the running os version string
1646      * @memberof cc.sys
1647      * @name osVersion
1648      * @type {String}
1649      */
1650     sys.osVersion = osVersion;
1651     /**
1652      * Indicate the running os main version number
1653      * @memberof cc.sys
1654      * @name osMainVersion
1655      * @type {Number}
1656      */
1657     sys.osMainVersion = osMainVersion;
1658 
1659     /**
1660      * Indicate the running browser type
1661      * @memberof cc.sys
1662      * @name browserType
1663      * @type {String}
1664      */
1665     sys.browserType = sys.BROWSER_TYPE_UNKNOWN;
1666     /* Determine the browser type */
1667     (function(){
1668         var typeReg1 = /sogou|qzone|liebao|micromessenger|ucbrowser|360 aphone|360browser|baiduboxapp|baidubrowser|maxthon|mxbrowser|trident|miuibrowser/i;
1669         var typeReg2 = /qqbrowser|chrome|safari|firefox|opr|oupeng|opera/i;
1670         var browserTypes = typeReg1.exec(ua);
1671         if(!browserTypes) browserTypes = typeReg2.exec(ua);
1672         var browserType = browserTypes ? browserTypes[0] : sys.BROWSER_TYPE_UNKNOWN;
1673         if (browserType === 'micromessenger')
1674             browserType = sys.BROWSER_TYPE_WECHAT;
1675         else if (browserType === "safari" && (ua.match(/android.*applewebkit/)))
1676             browserType = sys.BROWSER_TYPE_ANDROID;
1677         else if (browserType === "trident")
1678             browserType = sys.BROWSER_TYPE_IE;
1679         else if (browserType === "360 aphone")
1680             browserType = sys.BROWSER_TYPE_360;
1681         else if (browserType === "mxbrowser")
1682             browserType = sys.BROWSER_TYPE_MAXTHON;
1683         else if (browserType === "opr")
1684             browserType = sys.BROWSER_TYPE_OPERA;
1685 
1686         sys.browserType = browserType;
1687     })();
1688 
1689     /**
1690      * Indicate the running browser version
1691      * @memberof cc.sys
1692      * @name browserVersion
1693      * @type {Number}
1694      */
1695     sys.browserVersion = "";
1696     /* Determine the browser version number */
1697     (function(){
1698         var versionReg1 = /(micromessenger|mx|maxthon|baidu|sogou)(mobile)?(browser)?\/?([\d.]+)/i;
1699         var versionReg2 = /(msie |rv:|firefox|chrome|ucbrowser|qq|oupeng|opera|opr|safari|miui)(mobile)?(browser)?\/?([\d.]+)/i;
1700         var tmp = ua.match(versionReg1);
1701         if(!tmp) tmp = ua.match(versionReg2);
1702         sys.browserVersion = tmp ? tmp[4] : "";
1703     })();
1704 
1705     var w = window.innerWidth || document.documentElement.clientWidth;
1706     var h = window.innerHeight || document.documentElement.clientHeight;
1707     var ratio = window.devicePixelRatio || 1;
1708 
1709     /**
1710      * Indicate the real pixel resolution of the whole game window
1711      * @memberof cc.sys
1712      * @name windowPixelResolution
1713      * @type {Number}
1714      */
1715     sys.windowPixelResolution = {
1716         width: ratio * w,
1717         height: ratio * h
1718     };
1719 
1720     sys._checkWebGLRenderMode = function () {
1721         if (cc._renderType !== cc.game.RENDER_TYPE_WEBGL)
1722             throw new Error("This feature supports WebGL render mode only.");
1723     };
1724 
1725     //Whether or not the Canvas BlendModes are supported.
1726     sys._supportCanvasNewBlendModes = (function(){
1727         var canvas = _tmpCanvas1;
1728         canvas.width = 1;
1729         canvas.height = 1;
1730         var context = canvas.getContext('2d');
1731         context.fillStyle = '#000';
1732         context.fillRect(0,0,1,1);
1733         context.globalCompositeOperation = 'multiply';
1734 
1735         var canvas2 = _tmpCanvas2;
1736         canvas2.width = 1;
1737         canvas2.height = 1;
1738         var context2 = canvas2.getContext('2d');
1739         context2.fillStyle = '#fff';
1740         context2.fillRect(0,0,1,1);
1741         context.drawImage(canvas2, 0, 0, 1, 1);
1742 
1743         return context.getImageData(0,0,1,1).data[0] === 0;
1744     })();
1745 
1746     // Adjust mobile css settings
1747     if (cc.sys.isMobile) {
1748         var fontStyle = document.createElement("style");
1749         fontStyle.type = "text/css";
1750         document.body.appendChild(fontStyle);
1751 
1752         fontStyle.textContent = "body,canvas,div{ -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;"
1753                                 + "-webkit-tap-highlight-color:rgba(0,0,0,0);}";
1754     }
1755 
1756     /**
1757      * cc.sys.localStorage is a local storage component.
1758      * @memberof cc.sys
1759      * @name localStorage
1760      * @type {Object}
1761      */
1762     try {
1763         var localStorage = sys.localStorage = win.localStorage;
1764         localStorage.setItem("storage", "");
1765         localStorage.removeItem("storage");
1766         localStorage = null;
1767     } catch (e) {
1768         var warn = function () {
1769             cc.warn("Warning: localStorage isn't enabled. Please confirm browser cookie or privacy option");
1770         };
1771         sys.localStorage = {
1772             getItem : warn,
1773             setItem : warn,
1774             removeItem : warn,
1775             clear : warn
1776         };
1777     }
1778 
1779     var _supportCanvas = !!_tmpCanvas1.getContext("2d");
1780     var _supportWebGL = false;
1781     var tmpCanvas = document.createElement("CANVAS");
1782     if (win.WebGLRenderingContext) {
1783         try{
1784             var context = cc.create3DContext(tmpCanvas, {'stencil': true, 'preserveDrawingBuffer': true });
1785             if(context) {
1786                 _supportWebGL = true;
1787             }
1788         }
1789         catch (e) {}
1790     }
1791 
1792     /**
1793      * The capabilities of the current platform
1794      * @memberof cc.sys
1795      * @name capabilities
1796      * @type {Object}
1797      */
1798     var capabilities = sys.capabilities = {
1799         "canvas": _supportCanvas,
1800         "opengl": _supportWebGL
1801     };
1802     if (docEle['ontouchstart'] !== undefined || doc['ontouchstart'] !== undefined || nav.msPointerEnabled)
1803         capabilities["touches"] = true;
1804     if (docEle['onmouseup'] !== undefined)
1805         capabilities["mouse"] = true;
1806     if (docEle['onkeyup'] !== undefined)
1807         capabilities["keyboard"] = true;
1808     if (win.DeviceMotionEvent || win.DeviceOrientationEvent)
1809         capabilities["accelerometer"] = true;
1810 
1811     /**
1812      * Forces the garbage collection, only available in JSB
1813      * @memberof cc.sys
1814      * @name garbageCollect
1815      * @function
1816      */
1817     sys.garbageCollect = function () {
1818         // N/A in cocos2d-html5
1819     };
1820 
1821     /**
1822      * Dumps rooted objects, only available in JSB
1823      * @memberof cc.sys
1824      * @name dumpRoot
1825      * @function
1826      */
1827     sys.dumpRoot = function () {
1828         // N/A in cocos2d-html5
1829     };
1830 
1831     /**
1832      * Restart the JS VM, only available in JSB
1833      * @memberof cc.sys
1834      * @name restartVM
1835      * @function
1836      */
1837     sys.restartVM = function () {
1838         // N/A in cocos2d-html5
1839     };
1840 
1841     /**
1842      * Clean a script in the JS VM, only available in JSB
1843      * @memberof cc.sys
1844      * @name cleanScript
1845      * @param {String} jsfile
1846      * @function
1847      */
1848     sys.cleanScript = function (jsfile) {
1849         // N/A in cocos2d-html5
1850     };
1851 
1852     /**
1853      * Check whether an object is valid,
1854      * In web engine, it will return true if the object exist
1855      * In native engine, it will return true if the JS object and the correspond native object are both valid
1856      * @memberof cc.sys
1857      * @name isObjectValid
1858      * @param {Object} obj
1859      * @return {boolean} Validity of the object
1860      * @function
1861      */
1862     sys.isObjectValid = function (obj) {
1863         if (obj) return true;
1864         else return false;
1865     };
1866 
1867     /**
1868      * Dump system informations
1869      * @memberof cc.sys
1870      * @name dump
1871      * @function
1872      */
1873     sys.dump = function () {
1874         var self = this;
1875         var str = "";
1876         str += "isMobile : " + self.isMobile + "\r\n";
1877         str += "language : " + self.language + "\r\n";
1878         str += "browserType : " + self.browserType + "\r\n";
1879         str += "capabilities : " + JSON.stringify(self.capabilities) + "\r\n";
1880         str += "os : " + self.os + "\r\n";
1881         str += "platform : " + self.platform + "\r\n";
1882         cc.log(str);
1883     };
1884 
1885     /**
1886      * Open a url in browser
1887      * @memberof cc.sys
1888      * @name openURL
1889      * @param {String} url
1890      */
1891     sys.openURL = function(url){
1892         window.open(url);
1893     };
1894 };
1895 _initSys();
1896 
1897 delete _tmpCanvas1;
1898 delete _tmpCanvas2;
1899 
1900 //to make sure the cc.log, cc.warn, cc.error and cc.assert would not throw error before init by debugger mode.
1901 cc.log = cc.warn = cc.error = cc.assert = function () {
1902 };
1903 
1904 var _config = null,
1905     //cache for js and module that has added into jsList to be loaded.
1906     _jsAddedCache = {},
1907     _engineInitCalled = false,
1908     _engineLoadedCallback = null;
1909 
1910 cc._engineLoaded = false;
1911 
1912 function _determineRenderType(config) {
1913     var CONFIG_KEY = cc.game.CONFIG_KEY,
1914         userRenderMode = parseInt(config[CONFIG_KEY.renderMode]) || 0,
1915         shieldOs = [cc.sys.OS_ANDROID],
1916         shieldBrowser = [];
1917 
1918     // Adjust RenderType
1919     if (isNaN(userRenderMode) || userRenderMode > 2 || userRenderMode < 0)
1920         config[CONFIG_KEY.renderMode] = 0;
1921 
1922     // Determine RenderType
1923     cc._renderType = cc.game.RENDER_TYPE_CANVAS;
1924     cc._supportRender = true;
1925 
1926     if ( userRenderMode === 2 || 
1927         (   userRenderMode === 0 && 
1928             shieldOs.indexOf(cc.sys.os) === -1 && 
1929             shieldBrowser.indexOf(cc.sys.browserType) === -1 )) {
1930         if (cc.sys.capabilities["opengl"]) {
1931             cc._renderType = cc.game.RENDER_TYPE_WEBGL;
1932             cc._supportRender = true;
1933         }
1934         else {
1935             cc._supportRender = false;
1936         }
1937     }
1938     if (userRenderMode === 1
1939         || (userRenderMode === 0 && !cc._supportRender)) {
1940         if (cc.sys.capabilities["canvas"]) {
1941             cc._renderType = cc.game.RENDER_TYPE_CANVAS;
1942             cc._supportRender = true;
1943         }
1944         else {
1945             cc._supportRender = false;
1946         }
1947     }
1948 }
1949 
1950 function _getJsListOfModule(moduleMap, moduleName, dir) {
1951     if (_jsAddedCache[moduleName]) return null;
1952     dir = dir || "";
1953     var jsList = [];
1954     var tempList = moduleMap[moduleName];
1955     if (!tempList) throw new Error("can not find module [" + moduleName + "]");
1956     var ccPath = cc.path;
1957     for (var i = 0, li = tempList.length; i < li; i++) {
1958         var item = tempList[i];
1959         if (_jsAddedCache[item]) continue;
1960         var extname = ccPath.extname(item);
1961         if (!extname) {
1962             var arr = _getJsListOfModule(moduleMap, item, dir);
1963             if (arr) jsList = jsList.concat(arr);
1964         } else if (extname.toLowerCase() === ".js") jsList.push(ccPath.join(dir, item));
1965         _jsAddedCache[item] = 1;
1966     }
1967     return jsList;
1968 }
1969 
1970 function _afterEngineLoaded(config) {
1971     cc._initDebugSetting(config[cc.game.CONFIG_KEY.debugMode]);
1972     cc._engineLoaded = true;
1973     cc.log(cc.ENGINE_VERSION);
1974     if (_engineLoadedCallback) _engineLoadedCallback();
1975 }
1976 
1977 function _load(config) {
1978     var self = this;
1979     var CONFIG_KEY = cc.game.CONFIG_KEY, engineDir = config[CONFIG_KEY.engineDir], loader = cc.loader;
1980 
1981     if (cc.Class) {
1982         // Single file loaded
1983         _afterEngineLoaded(config);
1984     } else {
1985         // Load cocos modules
1986         var ccModulesPath = cc.path.join(engineDir, "moduleConfig.json");
1987         loader.loadJson(ccModulesPath, function (err, modulesJson) {
1988             if (err) throw new Error(err);
1989             var modules = config["modules"] || [];
1990             var moduleMap = modulesJson["module"];
1991             var jsList = [];
1992             if (cc.sys.capabilities["opengl"] && modules.indexOf("base4webgl") < 0) modules.splice(0, 0, "base4webgl");
1993             else if (modules.indexOf("core") < 0) modules.splice(0, 0, "core");
1994             for (var i = 0, li = modules.length; i < li; i++) {
1995                 var arr = _getJsListOfModule(moduleMap, modules[i], engineDir);
1996                 if (arr) jsList = jsList.concat(arr);
1997             }
1998             cc.loader.loadJsWithImg(jsList, function (err) {
1999                 if (err) throw err;
2000                 _afterEngineLoaded(config);
2001             });
2002         });
2003     }
2004 }
2005 
2006 function _windowLoaded() {
2007     this.removeEventListener('load', _windowLoaded, false);
2008     _load(cc.game.config);
2009 }
2010 
2011 cc.initEngine = function (config, cb) {
2012     if (_engineInitCalled) {
2013         var previousCallback = _engineLoadedCallback;
2014         _engineLoadedCallback = function () {
2015             previousCallback && previousCallback();
2016             cb && cb();
2017         }
2018         return;
2019     }
2020 
2021     _engineLoadedCallback = cb;
2022 
2023     // Config uninitialized and given, initialize with it
2024     if (!cc.game.config && config) {
2025         cc.game.config = config;
2026     }
2027     // No config given and no config set before, load it
2028     else if (!cc.game.config) {
2029         cc.game._loadConfig();
2030     }
2031     config = cc.game.config;
2032 
2033     _determineRenderType(config);
2034 
2035     document.body ? _load(config) : cc._addEventListener(window, 'load', _windowLoaded, false);
2036     _engineInitCalled = true;
2037 }
2038 
2039 })();
2040 //+++++++++++++++++++++++++Engine initialization function end+++++++++++++++++++++++++++++
2041 
2042 //+++++++++++++++++++++++++something about CCGame begin+++++++++++++++++++++++++++
2043 /**
2044  * An object to boot the game.
2045  * @class
2046  * @name cc.game
2047  */
2048 cc.game = /** @lends cc.game# */{
2049     DEBUG_MODE_NONE: 0,
2050     DEBUG_MODE_INFO: 1,
2051     DEBUG_MODE_WARN: 2,
2052     DEBUG_MODE_ERROR: 3,
2053     DEBUG_MODE_INFO_FOR_WEB_PAGE: 4,
2054     DEBUG_MODE_WARN_FOR_WEB_PAGE: 5,
2055     DEBUG_MODE_ERROR_FOR_WEB_PAGE: 6,
2056 
2057     EVENT_HIDE: "game_on_hide",
2058     EVENT_SHOW: "game_on_show",
2059     EVENT_RESIZE: "game_on_resize",
2060     EVENT_RENDERER_INITED: "renderer_inited",
2061 
2062     RENDER_TYPE_CANVAS: 0,
2063     RENDER_TYPE_WEBGL: 1,
2064     RENDER_TYPE_OPENGL: 2,
2065 
2066     _eventHide: null,
2067     _eventShow: null,
2068 
2069     /**
2070      * Key of config
2071      * @constant
2072      * @type {Object}
2073      */
2074     CONFIG_KEY: {
2075         width: "width",
2076         height: "height",
2077         engineDir: "engineDir",
2078         modules: "modules",
2079         debugMode: "debugMode",
2080         showFPS: "showFPS",
2081         frameRate: "frameRate",
2082         id: "id",
2083         renderMode: "renderMode",
2084         jsList: "jsList"
2085     },
2086     
2087     // states
2088     _paused: true,//whether the game is paused
2089     _prepareCalled: false,//whether the prepare function has been called
2090     _prepared: false,//whether the engine has prepared
2091     _rendererInitialized: false,
2092 
2093     _renderContext: null,
2094     
2095     _intervalId: null,//interval target of main
2096     
2097     _lastTime: null,
2098     _frameTime: null,
2099 
2100     /**
2101      * The outer frame of the game canvas, parent of cc.container
2102      * @type {Object}
2103      */
2104     frame: null,
2105     /**
2106      * The container of game canvas, equals to cc.container
2107      * @type {Object}
2108      */
2109     container: null,
2110     /**
2111      * The canvas of the game, equals to cc._canvas
2112      * @type {Object}
2113      */
2114     canvas: null,
2115 
2116     /**
2117      * Config of game
2118      * @type {Object}
2119      */
2120     config: null,
2121 
2122     /**
2123      * Callback when the scripts of engine have been load.
2124      * @type {Function}
2125      */
2126     onStart: null,
2127 
2128     /**
2129      * Callback when game exits.
2130      * @type {Function}
2131      */
2132     onStop: null,
2133 
2134 //@Public Methods
2135 
2136 //  @Game play control
2137     /**
2138      * Set frameRate of game.
2139      * @param frameRate
2140      */
2141     setFrameRate: function (frameRate) {
2142         var self = this, config = self.config, CONFIG_KEY = self.CONFIG_KEY;
2143         config[CONFIG_KEY.frameRate] = frameRate;
2144         if (self._intervalId)
2145             window.cancelAnimationFrame(self._intervalId);
2146         self._paused = true;
2147         self._setAnimFrame();
2148         self._runMainLoop();
2149     },
2150 
2151     /**
2152      * Run the game frame by frame.
2153      */
2154     step: function () {
2155         cc.director.mainLoop();
2156     },
2157 
2158     /**
2159      * Pause the game.
2160      */
2161     pause: function () {
2162         if (this._paused) return;
2163         this._paused = true;
2164         // Pause audio engine
2165         cc.audioEngine && cc.audioEngine._pausePlaying();
2166         // Pause main loop
2167         if (this._intervalId)
2168             window.cancelAnimationFrame(this._intervalId);
2169         this._intervalId = 0;
2170     },
2171 
2172     /**
2173      * Resume the game from pause.
2174      */
2175     resume: function () {
2176         if (!this._paused) return;
2177         this._paused = false;
2178         // Resume audio engine
2179         cc.audioEngine && cc.audioEngine._resumePlaying();
2180         // Resume main loop
2181         this._runMainLoop();
2182     },
2183 
2184     /**
2185      * Check whether the game is paused.
2186      */
2187     isPaused: function () {
2188         return this._paused;
2189     },
2190 
2191     /**
2192      * Restart game.
2193      */
2194     restart: function () {
2195         cc.director.popToSceneStackLevel(0);
2196         // Clean up audio
2197         cc.audioEngine && cc.audioEngine.end();
2198 
2199         cc.game.onStart();
2200     },
2201 
2202 //  @Game loading
2203     /**
2204      * Prepare game.
2205      * @param cb
2206      */
2207     prepare: function (cb) {
2208         var self = this,
2209             config = self.config, 
2210             CONFIG_KEY = self.CONFIG_KEY;
2211 
2212         this._loadConfig();
2213 
2214         // Already prepared
2215         if (this._prepared) {
2216             if (cb) cb();
2217             return;
2218         }
2219         // Prepare called, but not done yet
2220         if (this._prepareCalled) {
2221             return;
2222         }
2223         // Prepare never called and engine ready
2224         if (cc._engineLoaded) {
2225             this._prepareCalled = true;
2226 
2227             this._initRenderer(config[CONFIG_KEY.width], config[CONFIG_KEY.height]);
2228 
2229             /**
2230              * @type {cc.EGLView}
2231              * @name cc.view
2232              * @memberof cc
2233              * cc.view is the shared view object.
2234              */
2235             cc.view = cc.EGLView._getInstance();
2236 
2237             /**
2238              * @type {cc.Director}
2239              * @name cc.director
2240              * @memberof cc
2241              */
2242             cc.director = cc.Director._getInstance();
2243             if (cc.director.setOpenGLView)
2244                 cc.director.setOpenGLView(cc.view);
2245             /**
2246              * @type {cc.Size}
2247              * @name cc.winSize
2248              * @memberof cc
2249              * cc.winSize is the alias object for the size of the current game window.
2250              */
2251             cc.winSize = cc.director.getWinSize();
2252 
2253             this._initEvents();
2254 
2255             this._setAnimFrame();
2256             this._runMainLoop();
2257 
2258             // Load game scripts
2259             var jsList = config[CONFIG_KEY.jsList];
2260             if (jsList) {
2261                 cc.loader.loadJsWithImg(jsList, function (err) {
2262                     if (err) throw new Error(err);
2263                     self._prepared = true;
2264                     if (cb) cb();
2265                 });
2266             }
2267             else {
2268                 if (cb) cb();
2269             }
2270 
2271             return;
2272         }
2273 
2274         // Engine not loaded yet
2275         cc.initEngine(this.config, function () {
2276             self.prepare(cb);
2277         });
2278     },
2279 
2280     /**
2281      * Run game with configuration object and onStart function.
2282      * @param {Object|Function} [config] Pass configuration object or onStart function
2283      * @param {onStart} [onStart] onStart function to be executed after game initialized
2284      */
2285     run: function (config, onStart) {
2286         if (typeof config === 'function') {
2287             cc.game.onStart = config;
2288         }
2289         else {
2290             if (config) {
2291                 if (typeof config === 'string') {
2292                     if (!cc.game.config) this._loadConfig();
2293                     cc.game.config[cc.game.CONFIG_KEY.id] = config;
2294                 } else {
2295                     cc.game.config = config;
2296                 }
2297             }
2298             if (typeof onStart === 'function') {
2299                 cc.game.onStart = onStart;
2300             }
2301         }
2302         
2303         this.prepare(cc.game.onStart && cc.game.onStart.bind(cc.game));
2304     },
2305 
2306 //@Private Methods
2307 
2308 //  @Time ticker section
2309     _setAnimFrame: function () {
2310         this._lastTime = new Date();
2311         this._frameTime = 1000 / cc.game.config[cc.game.CONFIG_KEY.frameRate];
2312         if((cc.sys.os === cc.sys.OS_IOS && cc.sys.browserType === cc.sys.BROWSER_TYPE_WECHAT) || cc.game.config[cc.game.CONFIG_KEY.frameRate] !== 60) {
2313             window.requestAnimFrame = this._stTime;
2314             window.cancelAnimationFrame = this._ctTime;
2315         }
2316         else {
2317             window.requestAnimFrame = window.requestAnimationFrame ||
2318             window.webkitRequestAnimationFrame ||
2319             window.mozRequestAnimationFrame ||
2320             window.oRequestAnimationFrame ||
2321             window.msRequestAnimationFrame ||
2322             this._stTime;
2323             window.cancelAnimationFrame = window.cancelAnimationFrame ||
2324             window.cancelRequestAnimationFrame ||
2325             window.msCancelRequestAnimationFrame ||
2326             window.mozCancelRequestAnimationFrame ||
2327             window.oCancelRequestAnimationFrame ||
2328             window.webkitCancelRequestAnimationFrame ||
2329             window.msCancelAnimationFrame ||
2330             window.mozCancelAnimationFrame ||
2331             window.webkitCancelAnimationFrame ||
2332             window.oCancelAnimationFrame ||
2333             this._ctTime;
2334         }
2335     },
2336     _stTime: function(callback){
2337         var currTime = new Date().getTime();
2338         var timeToCall = Math.max(0, cc.game._frameTime - (currTime - cc.game._lastTime));
2339         var id = window.setTimeout(function() { callback(); },
2340             timeToCall);
2341         cc.game._lastTime = currTime + timeToCall;
2342         return id;
2343     },
2344     _ctTime: function(id){
2345         window.clearTimeout(id);
2346     },
2347     //Run game.
2348     _runMainLoop: function () {
2349         var self = this, callback, config = self.config, CONFIG_KEY = self.CONFIG_KEY,
2350             director = cc.director;
2351 
2352         director.setDisplayStats(config[CONFIG_KEY.showFPS]);
2353 
2354         callback = function () {
2355             if (!self._paused) {
2356                 director.mainLoop();
2357                 if(self._intervalId)
2358                     window.cancelAnimationFrame(self._intervalId);
2359                 self._intervalId = window.requestAnimFrame(callback);
2360             }
2361         };
2362 
2363         window.requestAnimFrame(callback);
2364         self._paused = false;
2365     },
2366 
2367 //  @Game loading section
2368     _loadConfig: function () {
2369         // Load config
2370         // Already loaded
2371         if (this.config) {
2372             this._initConfig(this.config);
2373             return;
2374         }
2375         // Load from document.ccConfig
2376         if (document["ccConfig"]) {
2377             this._initConfig(document["ccConfig"]);
2378         }
2379         // Load from project.json 
2380         else {
2381             try {
2382                 var cocos_script = document.getElementsByTagName('script');
2383                 for(var i = 0; i < cocos_script.length; i++){
2384                     var _t = cocos_script[i].getAttribute('cocos');
2385                     if(_t === '' || _t) {
2386                         break;
2387                     }
2388                 }
2389                 var _src, txt, _resPath;
2390                 if(i < cocos_script.length){
2391                     _src = cocos_script[i].src;
2392                     if(_src){
2393                         _resPath = /(.*)\//.exec(_src)[0];
2394                         cc.loader.resPath = _resPath;
2395                         _src = cc.path.join(_resPath, 'project.json');
2396                     }
2397                     txt = cc.loader._loadTxtSync(_src);
2398                 }
2399                 if(!txt){
2400                     txt = cc.loader._loadTxtSync("project.json");
2401                 }
2402                 var data = JSON.parse(txt);
2403                 this._initConfig(data || {});
2404             } catch (e) {
2405                 cc.log("Failed to read or parse project.json");
2406                 this._initConfig({});
2407             }
2408         }
2409     },
2410 
2411     _initConfig: function (config) {
2412         var CONFIG_KEY = this.CONFIG_KEY,
2413             modules = config[CONFIG_KEY.modules];
2414 
2415         // Configs adjustment
2416         config[CONFIG_KEY.showFPS] = typeof config[CONFIG_KEY.showFPS] === 'undefined' ? true : config[CONFIG_KEY.showFPS];
2417         config[CONFIG_KEY.engineDir] = config[CONFIG_KEY.engineDir] || "frameworks/cocos2d-html5";
2418         if (config[CONFIG_KEY.debugMode] == null)
2419             config[CONFIG_KEY.debugMode] = 0;
2420         config[CONFIG_KEY.frameRate] = config[CONFIG_KEY.frameRate] || 60;
2421         if (config[CONFIG_KEY.renderMode] == null)
2422             config[CONFIG_KEY.renderMode] = 0;
2423         if (config[CONFIG_KEY.registerSystemEvent] == null)
2424             config[CONFIG_KEY.registerSystemEvent] = true;
2425 
2426         // Modules adjustment
2427         if (modules && modules.indexOf("core") < 0) modules.splice(0, 0, "core");
2428         modules && (config[CONFIG_KEY.modules] = modules);
2429         this.config = config;
2430     },
2431 
2432     _initRenderer: function (width, height) {
2433         // Avoid setup to be called twice.
2434         if (this._rendererInitialized) return;
2435 
2436         if (!cc._supportRender) {
2437             throw new Error("The renderer doesn't support the renderMode " + this.config[this.CONFIG_KEY.renderMode]);
2438         }
2439 
2440         var el = this.config[cc.game.CONFIG_KEY.id],
2441             win = window,
2442             element = cc.$(el) || cc.$('#' + el),
2443             localCanvas, localContainer, localConStyle;
2444 
2445         if (element.tagName === "CANVAS") {
2446             width = width || element.width;
2447             height = height || element.height;
2448 
2449             //it is already a canvas, we wrap it around with a div
2450             this.canvas = cc._canvas = localCanvas = element;
2451             this.container = cc.container = localContainer = document.createElement("DIV");
2452             if (localCanvas.parentNode)
2453                 localCanvas.parentNode.insertBefore(localContainer, localCanvas);
2454         } else {
2455             //we must make a new canvas and place into this element
2456             if (element.tagName !== "DIV") {
2457                 cc.log("Warning: target element is not a DIV or CANVAS");
2458             }
2459             width = width || element.clientWidth;
2460             height = height || element.clientHeight;
2461             this.canvas = cc._canvas = localCanvas = document.createElement("CANVAS");
2462             this.container = cc.container = localContainer = document.createElement("DIV");
2463             element.appendChild(localContainer);
2464         }
2465         localContainer.setAttribute('id', 'Cocos2dGameContainer');
2466         localContainer.appendChild(localCanvas);
2467         this.frame = (localContainer.parentNode === document.body) ? document.documentElement : localContainer.parentNode;
2468 
2469         localCanvas.addClass("gameCanvas");
2470         localCanvas.setAttribute("width", width || 480);
2471         localCanvas.setAttribute("height", height || 320);
2472         localCanvas.setAttribute("tabindex", 99);
2473         localCanvas.style.outline = "none";
2474         localConStyle = localContainer.style;
2475         localConStyle.width = (width || 480) + "px";
2476         localConStyle.height = (height || 320) + "px";
2477         localConStyle.margin = "0 auto";
2478 
2479         localConStyle.position = 'relative';
2480         localConStyle.overflow = 'hidden';
2481         localContainer.top = '100%';
2482 
2483         if (cc._renderType === cc.game.RENDER_TYPE_WEBGL) {
2484             this._renderContext = cc._renderContext = cc.webglContext
2485              = cc.create3DContext(localCanvas, {
2486                 'stencil': true,
2487                 'preserveDrawingBuffer': true,
2488                 'antialias': !cc.sys.isMobile,
2489                 'alpha': true
2490             });
2491         }
2492         // WebGL context created successfully
2493         if (this._renderContext) {
2494             cc.renderer = cc.rendererWebGL;
2495             win.gl = this._renderContext; // global variable declared in CCMacro.js
2496             cc.shaderCache._init();
2497             cc._drawingUtil = new cc.DrawingPrimitiveWebGL(this._renderContext);
2498             cc.textureCache._initializingRenderer();
2499         } else {
2500             cc.renderer = cc.rendererCanvas;
2501             this._renderContext = cc._renderContext = new cc.CanvasContextWrapper(localCanvas.getContext("2d"));
2502             cc._drawingUtil = cc.DrawingPrimitiveCanvas ? new cc.DrawingPrimitiveCanvas(this._renderContext) : null;
2503         }
2504 
2505         cc._gameDiv = localContainer;
2506         cc.game.canvas.oncontextmenu = function () {
2507             if (!cc._isContextMenuEnable) return false;
2508         };
2509 
2510         this.dispatchEvent(this.EVENT_RENDERER_INITED, true);
2511 
2512         this._rendererInitialized = true;
2513     },
2514 
2515     _initEvents: function () {
2516         var win = window, self = this, hidden, visibilityChange, _undef = "undefined";
2517 
2518         this._eventHide = this._eventHide || new cc.EventCustom(this.EVENT_HIDE);
2519         this._eventHide.setUserData(this);
2520         this._eventShow = this._eventShow || new cc.EventCustom(this.EVENT_SHOW);
2521         this._eventShow.setUserData(this);
2522 
2523         // register system events
2524         if (this.config[this.CONFIG_KEY.registerSystemEvent])
2525             cc.inputManager.registerSystemEvent(this.canvas);
2526 
2527         if (!cc.isUndefined(document.hidden)) {
2528             hidden = "hidden";
2529             visibilityChange = "visibilitychange";
2530         } else if (!cc.isUndefined(document.mozHidden)) {
2531             hidden = "mozHidden";
2532             visibilityChange = "mozvisibilitychange";
2533         } else if (!cc.isUndefined(document.msHidden)) {
2534             hidden = "msHidden";
2535             visibilityChange = "msvisibilitychange";
2536         } else if (!cc.isUndefined(document.webkitHidden)) {
2537             hidden = "webkitHidden";
2538             visibilityChange = "webkitvisibilitychange";
2539         }
2540 
2541         var onHidden = function () {
2542             if (cc.eventManager && cc.game._eventHide)
2543                 cc.eventManager.dispatchEvent(cc.game._eventHide);
2544         };
2545         var onShow = function () {
2546             if (cc.eventManager && cc.game._eventShow)
2547                 cc.eventManager.dispatchEvent(cc.game._eventShow);
2548         };
2549 
2550         if (hidden) {
2551             document.addEventListener(visibilityChange, function () {
2552                 if (document[hidden]) onHidden();
2553                 else onShow();
2554             }, false);
2555         } else {
2556             win.addEventListener("blur", onHidden, false);
2557             win.addEventListener("focus", onShow, false);
2558         }
2559 
2560         if(navigator.userAgent.indexOf("MicroMessenger") > -1){
2561             win.onfocus = function(){ onShow() };
2562         }
2563 
2564         if ("onpageshow" in window && "onpagehide" in window) {
2565             win.addEventListener("pagehide", onHidden, false);
2566             win.addEventListener("pageshow", onShow, false);
2567         }
2568 
2569         cc.eventManager.addCustomListener(cc.game.EVENT_HIDE, function () {
2570             cc.game.pause();
2571         });
2572         cc.eventManager.addCustomListener(cc.game.EVENT_SHOW, function () {
2573             cc.game.resume();
2574         });
2575     }
2576 };
2577 //+++++++++++++++++++++++++something about CCGame end+++++++++++++++++++++++++++++
2578 
2579 Function.prototype.bind = Function.prototype.bind || function (oThis) {
2580     if (!cc.isFunction(this)) {
2581         // closest thing possible to the ECMAScript 5
2582         // internal IsCallable function
2583         throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
2584     }
2585 
2586     var aArgs = Array.prototype.slice.call(arguments, 1),
2587         fToBind = this,
2588         fNOP = function () {},
2589         fBound = function () {
2590             return fToBind.apply(this instanceof fNOP && oThis
2591                 ? this
2592                 : oThis,
2593                 aArgs.concat(Array.prototype.slice.call(arguments)));
2594         };
2595 
2596     fNOP.prototype = this.prototype;
2597     fBound.prototype = new fNOP();
2598 
2599     return fBound;
2600 };
2601 
2602 cc._urlRegExp = new RegExp(
2603     "^" +
2604         // protocol identifier
2605         "(?:(?:https?|ftp)://)" +
2606         // user:pass authentication
2607         "(?:\\S+(?::\\S*)?@)?" +
2608         "(?:" +
2609             // IP address dotted notation octets
2610             // excludes loopback network 0.0.0.0
2611             // excludes reserved space >= 224.0.0.0
2612             // excludes network & broacast addresses
2613             // (first & last IP address of each class)
2614             "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
2615             "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
2616             "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
2617         "|" +
2618             // host name
2619             "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" +
2620             // domain name
2621             "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" +
2622             // TLD identifier
2623             "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
2624         "|" +
2625             "(?:localhost)" +
2626         ")" +
2627         // port number
2628         "(?::\\d{2,5})?" +
2629         // resource path
2630         "(?:/\\S*)?" +
2631     "$", "i"
2632 );
2633